1 /***************************************************************************
2 *   Copyright (C) 2009 Matthias Fuchs <mat69@gmx.net>                     *
3 *   Copyright (C) 2012 Aish Raj Dahal <dahalaishraj@gmail.com>            *
4 *                                                                         *
5 *   This program is free software; you can redistribute it and/or modify  *
6 *   it under the terms of the GNU General Public License as published by  *
7 *   the Free Software Foundation; either version 2 of the License, or     *
8 *   (at your option) any later version.                                   *
9 *                                                                         *
10 *   This program is distributed in the hope that it will be useful,       *
11 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13 *   GNU General Public License for more details.                          *
14 *                                                                         *
15 *   You should have received a copy of the GNU General Public License     *
16 *   along with this program; if not, write to the                         *
17 *   Free Software Foundation, Inc.,                                       *
18 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
19 ***************************************************************************/
20 
21 #ifndef Metalinker_H
22 #define Metalinker_H
23 
24 #include <KIO/Job>
25 #include <QUrl>
26 #include <QDate>
27 #include <QDomElement>
28 #include <QEventLoop>
29 #include <QString>
30 #include <QObject>
31 
32 /**
33  * The following classes try to resemble the structure of a Metalink-document, they partially support
34  * the Metalink specification version 3.0 2nd ed and Draft 09
35  * It is possible to load and save metalinks and to edit them inbetween, you could also create a metalink
36  * from scratch
37  */
38 
39 namespace KGetMetalink
40 {
41 
42 class DateConstruct
43 {
44     public:
DateConstruct()45         DateConstruct()
46           : negativeOffset(false)
47         {
48         }
49 
50         void setData(const QDateTime &dateTime, const QTime &timeZoneOffset = QTime(), bool negativeOffset = false);
51         void setData(const QString &dateConstruct);
52 
53         void clear();
54 
55         bool isNull() const;
56         bool isValid() const;
57 
58         QString toString() const;
59 
60         QDateTime dateTime;
61         QTime timeZoneOffset;
62         bool negativeOffset;
63 };
64 
65 /**
66  * This class contains a url and the name, it can be used to e.g. describe a publisher
67  */
68 class UrlText
69 {
70     public:
UrlText()71         UrlText() {}
72 
isEmpty()73         bool isEmpty() const {return name.isEmpty() && url.isEmpty();}
74 
75         void clear();
76 
77         QString name;
78         QUrl url;
79 };
80 
81 /**
82 * Files, File and Metadata contain this
83 * Metadata not as member and only for compatibility
84 */
85 class CommonData
86 {
87     public:
CommonData()88         CommonData() {}
89 
90         void load(const QDomElement &e);
91         void save(QDomElement &e) const;
92 
93         void clear();
94 
95         QString identity;
96         QString version;
97         QString description;
98         QStringList oses;
99         QUrl logo;
100         QStringList languages;
101         UrlText publisher;
102         QString copyright;
103 };
104 
105 class Metaurl
106 {
107     public:
Metaurl()108         Metaurl()
109           : priority(0)
110         {
111         }
112 
113         /**
114          * "smaller" urls are less important than larger, larger urls should be preferred
115          */
116         bool operator<(const Metaurl &other) const;
117 
118         void load(const QDomElement &e);
119         void save(QDomElement &e) const;
120 
121         bool isValid();
122 
123         void clear();
124 
125         QString type;
126 
127         /**
128          * the priority of the urls, 1 is highest priority, 999999 lowest
129          * default is 0 as in not set and thus is ranked even behind 999999
130          */
131         uint priority;
132 
133         /**
134          * Optional the name of a file that should be get of that metaurl
135          */
136         QString name;
137 
138         QUrl url;
139 };
140 
141 class Url
142 {
143     public:
Url()144         Url()
145           : priority(0)
146         {
147         }
148 
149         /**
150          * "smaller" urls are less important than larger, larger urls should be preferred
151          */
152         bool operator<(const Url &other) const;
153 
154         void load(const QDomElement &e);
155         void save(QDomElement &e) const;
156 
157         bool isValid();
158 
159         void clear();
160 
161         /**
162          * the priority of the urls, 1 is highest priority, 999999 lowest
163          * default is 0 as in not set and thus is ranked even behind 999999
164          */
165         uint priority;
166 
167         /**
168          * the location of the server eg. "uk"
169          */
170         QString location;
171 
172         QUrl url;
173 };
174 
175 class Resources
176 {
177     public:
Resources()178         Resources() {}
179 
isValid()180         bool isValid() const {return !urls.isEmpty() || !metaurls.isEmpty();}
181 
182         void load(const QDomElement &e);
183         void save(QDomElement &e) const;
184 
185         void clear();
186 
187         QList<Url> urls;
188         QList<Metaurl> metaurls;
189 };
190 
191 class Pieces
192 {
193     public:
Pieces()194         Pieces()
195           : length(0)
196         {
197         }
198 
199         void load(const QDomElement &e);
200         void save(QDomElement &e) const;
201 
202         void clear();
203 
204         QString type;
205         KIO::filesize_t length;
206         QStringList hashes;
207 };
208 
209 class Verification
210 {
211     public:
Verification()212         Verification() {}
213 
214         void load(const QDomElement &e);
215         void save(QDomElement &e) const;
216 
217         void clear();
218 
219         QHash<QString, QString> hashes;
220         QList<Pieces> pieces;
221         QHash<QString, QString> signatures;
222 };
223 
224 class File
225 {
226     public:
File()227         File()
228           : size(0)
229         {
230         }
231 
232         void load(const QDomElement &e);
233         void save(QDomElement &e) const;
234 
235         void clear();
236 
237         bool isValid() const;
238 
239         /**
240          * Controls if the name attribute is valid, i.e. it is not empty and
241          * does not contain any directory traversal directives or information,
242          * as described in the Metalink 4.0 specification 4.1.2.1.
243          */
244         bool isValidNameAttribute() const;
245 
246         QString name;
247         Verification verification;
248         KIO::filesize_t size;
249         CommonData data;
250         Resources resources;
251 };
252 
253 class Files
254 {
255     public:
Files()256         Files() {}
257 
258         bool isValid() const;
259 
260         void load(const QDomElement &e);
261         void save(QDomElement &e) const;
262 
263         void clear();
264 
265         QList<File> files;
266 };
267 
268 class Metalink
269 {
270     public:
Metalink()271         Metalink()
272           : dynamic(false)
273         {
274         }
275 
276         /**
277          * checks if the minimum requirements of a metalink are met
278          * @return true if the minimum requirements are met
279          */
280         bool isValid() const;
281 
282         void load(const QDomElement &e);
283 
284         /**
285          * Save the metalink
286          * @return the QDomDocument containing the metalink
287          */
288         QDomDocument save() const;
289 
290         void clear();
291 
292         bool dynamic;
293         QString xmlns; //the xmlns value is ignored when saving, instead the data format described in the specification is always used
294         DateConstruct published; //when the metalink was published
295         QUrl origin;
296         QString generator;
297         DateConstruct updated; //when the metalink was updated
298         Files files;
299 
300         static const QString KGET_DESCRIPTION;
301         static const uint MAX_URL_PRIORITY; //maximum priority a Metalink 4.0 Url or Metaurl can have, not to be mixed up with the highest priority
302 };
303 
304 /**
305  * @class Metalink_v3
306  * Metalink version 3.0 2nd ed
307  * Used only for loading and saving, uses itself Metalink internally
308  */
309 class Metalink_v3
310 {
311     public:
312         Metalink_v3();
313 
314         Metalink metalink();
315         void setMetalink(const Metalink &metalink);
316 
317         void load(const QDomElement &e);
318 
319         /**
320          * Save the metalink
321          * @return the QDomDocument containing the metalink
322          */
323         QDomDocument save() const;
324 
325     private:
326         void parseFiles(const QDomElement &e);
327         Resources parseResources(const QDomElement &e);
328         DateConstruct parseDateConstruct(const QString &data);
329         CommonData parseCommonData(const QDomElement &e);
330 
331         /**
332          * Inherits CommonData, the inheritor inherits every settings
333          * from the ancestor it has not set itself
334          */
335         void inheritCommonData(const CommonData &ancestor, CommonData *inheritor);
336 
337         void saveFiles(QDomElement &e) const;
338         void saveResources(const Resources &resources, QDomElement &e) const;
339         void saveVerification(const Verification &verification, QDomElement &e) const;
340         void saveCommonData(const CommonData &data, QDomElement &e) const;
341         QString dateConstructToString(const DateConstruct &date) const;
342 
343     private:
344         Metalink m_metalink;
345         static const uint MAX_PREFERENCE;
346 };
347 
348 /**
349  * This class can handle the loading and saving of metalinks on the filesystem
350  */
351 class HandleMetalink
352 {
353     public:
354         /**
355          * Loads destination into metalink
356          * @param destination the place of the metalink in the filesystem
357          * @param metalink the instance of Metalink where the metalink will be stored
358          * @return return true if it worked
359          */
360         static bool load(const QUrl &destination, Metalink *metalink);
361 
362         /**
363          * Loads data into metalink
364          * @param data the contents of a metalink
365          * @param metalink the instance of Metalink where the metalink will be stored
366          * @return return true if it worked
367          */
368         static bool load(const QByteArray &data, Metalink *metalink);
369 
370         /**
371          * Saves metalink to destination
372          * @param destination the place where the metlink will be saved, the ending defines
373          * what version should be used: *.meta4 --> Metalink 4.0; *.metalink --> Metalink 3.0
374          * @param metalink the instance of metalink that will be written to the filesystem
375          * @return return true if it worked
376          */
377         static bool save(const QUrl &destination, Metalink *metalink);
378 
379 };
380 
381 class MetalinkHttpParser : public QObject
382 {
383     Q_OBJECT
384     public:
MetalinkHttpParser(const QUrl & Url)385         MetalinkHttpParser(const QUrl& Url)
386             : m_Url(Url), m_MetalinkHSatus(false) , m_EtagValue(QString(""))
387         {
388             checkMetalinkHttp();
389         }
390 
391         ~MetalinkHttpParser() override;
392 
393         /**
394          * @return true if m_Url is a metalink/http supported URL.
395          */
396 
397         bool isMetalinkHttp();
398 
399         /**
400          * @return the Url m_Url which is being tested for metalink
401          */
402 
403         QUrl getUrl();
404         QMultiMap<QString, QString>* getHeaderInfo();
405 
406         /**
407          * @return Returns the ETag if present in the HTTP headers
408          */
409 
410         QString* getEtag();
411 
412     private Q_SLOTS:
413         void slotHeaderResult(KJob* kjob);
414         void checkMetalinkHttp();
415         void detectMime(KIO::Job *  job, const QString &  type);
416         void slotRedirection(KIO::Job*, const QUrl&);
417 
418 
419     private:
420         QUrl m_Url;
421         QUrl m_redirectionUrl;
422         bool m_MetalinkHSatus;
423         QEventLoop m_loop;
424         QMultiMap<QString, QString> m_headerInfo;
425         QString m_EtagValue ;
426 
427         /**
428          * Parsees the Metalink values from QString to the Map
429          * @param Value of the QString ie raw HTTP headers
430          */
431         void parseHeaders(const QString&);
432 
433         /**
434          * Sets the status of m_MetalinkHStatus to true if the URL is a Metalink
435          */
436         void setMetalinkHSatus();
437 
438 };
439 
440 class HttpLinkHeader : public Metaurl
441 {
442     public:
443         HttpLinkHeader(const QString &headerLine);
444 
445         QString reltype;
446         bool pref;
447         int depth;
448         QString geo;
449 
450         /**
451          * Loads information from a header value into metalink header structure.
452          * @param line Value of the "link" HTTP header response.
453          */
454         void parseHeaderLine(const QString &);
455 
456         bool operator<(const HttpLinkHeader &) const;
457 };
458 
459 }
460 
461 #endif // Metalinker_H
462