mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-26 20:03:10 +00:00
1429 lines
41 KiB
C++
1429 lines
41 KiB
C++
/***************************************************************************
|
|
* Copyright (C) 2009 Matthias Fuchs <mat69@gmx.net> *
|
|
* Copyright (C) 2012 Aish Raj Dahal <dahalaishraj@gmail.com> *
|
|
* *
|
|
* 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. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
|
|
***************************************************************************/
|
|
|
|
#include "metalinker.h"
|
|
|
|
#include <QtCore/QFile>
|
|
#include <QtCore/QTextStream>
|
|
#include <QtXml/QDomElement>
|
|
|
|
#include <kdeversion.h>
|
|
#include <KDebug>
|
|
#include <KLocale>
|
|
#include <KSystemTimeZone>
|
|
|
|
|
|
const QString KGetMetalink::Metalink::KGET_DESCRIPTION = QString(QString("KGet/") + "2." + QString::number(KDE_VERSION_MINOR) + '.' + QString::number(KDE_VERSION_RELEASE));
|
|
const uint KGetMetalink::Metalink::MAX_URL_PRIORITY = 999999;
|
|
const uint KGetMetalink::Metalink_v3::MAX_PREFERENCE = 100;//as defined in Metalink specification 3.0 2nd edition
|
|
|
|
namespace KGetMetalink
|
|
{
|
|
QString addaptHashType(const QString &type, bool loaded);
|
|
}
|
|
|
|
/**
|
|
* Adapts type to the way the hash is internally stored
|
|
* @param type the hash-type
|
|
* @param load true if the hash has been loaded, false if it should be saved
|
|
* @note metalink wants sha1 in the form "sha-1", though
|
|
* the metalinker uses it internally in the form "sha1", this function
|
|
* transforms it to the correct form, it is only needed internally
|
|
*/
|
|
QString KGetMetalink::addaptHashType(const QString &type, bool loaded)
|
|
{
|
|
QString t = type;
|
|
if (loaded)
|
|
{
|
|
t.replace("sha-", "sha");
|
|
}
|
|
else
|
|
{
|
|
t.replace("sha", "sha-");
|
|
}
|
|
|
|
return t;
|
|
}
|
|
|
|
void KGetMetalink::DateConstruct::setData(const QDateTime &dateT, const QTime &timeZoneOff, bool negOff)
|
|
{
|
|
dateTime = dateT;
|
|
timeZoneOffset = timeZoneOff;
|
|
negativeOffset = negOff;
|
|
}
|
|
|
|
void KGetMetalink::DateConstruct::setData(const QString &dateConstruct)
|
|
{
|
|
if (dateConstruct.isEmpty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
const QString exp = "yyyy-MM-ddThh:mm:ss";
|
|
const int length = exp.length();
|
|
|
|
dateTime = QDateTime::fromString(dateConstruct.left(length), exp);
|
|
if (dateTime.isValid())
|
|
{
|
|
int index = dateConstruct.indexOf('+', length - 1);
|
|
if (index > -1)
|
|
{
|
|
timeZoneOffset = QTime::fromString(dateConstruct.mid(index + 1), "hh:mm");
|
|
}
|
|
else
|
|
{
|
|
index = dateConstruct.indexOf('-', length - 1);
|
|
if (index > -1)
|
|
{
|
|
negativeOffset = true;
|
|
timeZoneOffset = QTime::fromString(dateConstruct.mid(index + 1), "hh:mm");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool KGetMetalink::DateConstruct::isNull() const
|
|
{
|
|
return dateTime.isNull();
|
|
}
|
|
|
|
bool KGetMetalink::DateConstruct::isValid() const
|
|
{
|
|
return dateTime.isValid();
|
|
}
|
|
|
|
QString KGetMetalink::DateConstruct::toString() const
|
|
{
|
|
QString string;
|
|
|
|
if (dateTime.isValid())
|
|
{
|
|
string += dateTime.toString(Qt::ISODate);
|
|
}
|
|
|
|
if (timeZoneOffset.isValid())
|
|
{
|
|
string += (negativeOffset ? '-' : '+');
|
|
string += timeZoneOffset.toString("hh:mm");
|
|
}
|
|
else if (!string.isEmpty())
|
|
{
|
|
string += 'Z';
|
|
}
|
|
|
|
return string;
|
|
}
|
|
|
|
void KGetMetalink::DateConstruct::clear()
|
|
{
|
|
dateTime = QDateTime();
|
|
timeZoneOffset = QTime();
|
|
}
|
|
|
|
void KGetMetalink::UrlText::clear()
|
|
{
|
|
name.clear();
|
|
url.clear();
|
|
}
|
|
|
|
void KGetMetalink::CommonData::load(const QDomElement &e)
|
|
{
|
|
identity = e.firstChildElement("identity").text();
|
|
version = e.firstChildElement("version").text();
|
|
description = e.firstChildElement("description").text();
|
|
logo = KUrl(e.firstChildElement("logo").text());
|
|
copyright = e.firstChildElement("copyright").text();
|
|
|
|
const QDomElement publisherElem = e.firstChildElement("publisher");
|
|
publisher.name = publisherElem.attribute("name");
|
|
publisher.url = KUrl(publisherElem.attribute("url"));
|
|
|
|
for (QDomElement elemRes = e.firstChildElement("language"); !elemRes.isNull(); elemRes = elemRes.nextSiblingElement("language")) {
|
|
languages << elemRes.text();
|
|
}
|
|
|
|
for (QDomElement elemRes = e.firstChildElement("os"); !elemRes.isNull(); elemRes = elemRes.nextSiblingElement("os")) {
|
|
oses << elemRes.text();
|
|
}
|
|
}
|
|
|
|
void KGetMetalink::CommonData::save(QDomElement &e) const
|
|
{
|
|
QDomDocument doc = e.ownerDocument();
|
|
|
|
if (!copyright.isEmpty())
|
|
{
|
|
QDomElement elem = doc.createElement("copyright");
|
|
QDomText text = doc.createTextNode(copyright);
|
|
elem.appendChild(text);
|
|
e.appendChild(elem);
|
|
}
|
|
if (!description.isEmpty())
|
|
{
|
|
QDomElement elem = doc.createElement("description");
|
|
QDomText text = doc.createTextNode(description);
|
|
elem.appendChild(text);
|
|
e.appendChild(elem);
|
|
}
|
|
if (!identity.isEmpty())
|
|
{
|
|
QDomElement elem = doc.createElement("identity");
|
|
QDomText text = doc.createTextNode(identity);
|
|
elem.appendChild(text);
|
|
e.appendChild(elem);
|
|
}
|
|
if (!logo.isEmpty())
|
|
{
|
|
QDomElement elem = doc.createElement("logo");
|
|
QDomText text = doc.createTextNode(logo.url());
|
|
elem.appendChild(text);
|
|
e.appendChild(elem);
|
|
}
|
|
if (!publisher.isEmpty())
|
|
{
|
|
QDomElement elem = doc.createElement("publisher");
|
|
elem.setAttribute("url", publisher.url.url());
|
|
elem.setAttribute("name", publisher.name);
|
|
|
|
e.appendChild(elem);
|
|
}
|
|
if (!version.isEmpty())
|
|
{
|
|
QDomElement elem = doc.createElement("version");
|
|
QDomText text = doc.createTextNode(version);
|
|
elem.appendChild(text);
|
|
e.appendChild(elem);
|
|
}
|
|
|
|
foreach (const QString &language, languages) {
|
|
QDomElement elem = doc.createElement("language");
|
|
QDomText text = doc.createTextNode(language);
|
|
elem.appendChild(text);
|
|
e.appendChild(elem);
|
|
}
|
|
|
|
foreach (const QString &os, oses) {
|
|
QDomElement elem = doc.createElement("os");
|
|
QDomText text = doc.createTextNode(os);
|
|
elem.appendChild(text);
|
|
e.appendChild(elem);
|
|
}
|
|
}
|
|
|
|
void KGetMetalink::CommonData::clear()
|
|
{
|
|
identity.clear();
|
|
version.clear();
|
|
description.clear();
|
|
oses.clear();
|
|
logo.clear();
|
|
languages.clear();
|
|
publisher.clear();
|
|
copyright.clear();
|
|
}
|
|
|
|
|
|
|
|
bool KGetMetalink::Metaurl::operator<(const KGetMetalink::Metaurl &other) const
|
|
{
|
|
return (this->priority > other.priority) || (this->priority == 0);
|
|
}
|
|
|
|
void KGetMetalink::Metaurl::load(const QDomElement &e)
|
|
{
|
|
type = e.attribute("mediatype").toLower();
|
|
priority = e.attribute("priority").toUInt();
|
|
if (priority > Metalink::MAX_URL_PRIORITY) {
|
|
priority = Metalink::MAX_URL_PRIORITY;
|
|
}
|
|
name = e.attribute("name");
|
|
url = KUrl(e.text());
|
|
}
|
|
|
|
void KGetMetalink::Metaurl::save(QDomElement &e) const
|
|
{
|
|
QDomDocument doc = e.ownerDocument();
|
|
QDomElement metaurl = doc.createElement("metaurl");
|
|
if (priority)
|
|
{
|
|
metaurl.setAttribute("priority", priority);
|
|
}
|
|
if (!name.isEmpty())
|
|
{
|
|
metaurl.setAttribute("name", name);
|
|
}
|
|
metaurl.setAttribute("mediatype", type);
|
|
|
|
QDomText text = doc.createTextNode(url.url());
|
|
metaurl.appendChild(text);
|
|
|
|
e.appendChild(metaurl);
|
|
}
|
|
|
|
bool KGetMetalink::Metaurl::isValid()
|
|
{
|
|
return url.isValid() && url.hasHost() && !url.protocol().isEmpty() && !type.isEmpty();
|
|
}
|
|
|
|
void KGetMetalink::Metaurl::clear()
|
|
{
|
|
type.clear();
|
|
priority = 0;
|
|
name.clear();
|
|
url.clear();
|
|
}
|
|
|
|
bool KGetMetalink::Url::operator<(const KGetMetalink::Url &other) const
|
|
{
|
|
bool smaller = (this->priority > other.priority) || ((this->priority == 0) && (other.priority != 0));
|
|
|
|
if (!smaller && (this->priority == other.priority)) {
|
|
QString countryCode = KGlobal::locale()->country();
|
|
if (!countryCode.isEmpty()) {
|
|
smaller = (other.location.toLower() == countryCode.toLower());
|
|
}
|
|
}
|
|
return smaller;
|
|
}
|
|
|
|
void KGetMetalink::Url::load(const QDomElement &e)
|
|
{
|
|
location = e.attribute("location").toLower();
|
|
priority = e.attribute("priority").toUInt();
|
|
if (priority > Metalink::MAX_URL_PRIORITY) {
|
|
priority = Metalink::MAX_URL_PRIORITY;
|
|
}
|
|
url = KUrl(e.text());
|
|
}
|
|
|
|
void KGetMetalink::Url::save(QDomElement &e) const
|
|
{
|
|
QDomDocument doc = e.ownerDocument();
|
|
QDomElement elem = doc.createElement("url");
|
|
if (priority)
|
|
{
|
|
elem.setAttribute("priority", priority);
|
|
}
|
|
if (!location.isEmpty())
|
|
{
|
|
elem.setAttribute("location", location);
|
|
}
|
|
|
|
QDomText text = doc.createTextNode(url.url());
|
|
elem.appendChild(text);
|
|
|
|
e.appendChild(elem);
|
|
}
|
|
|
|
bool KGetMetalink::Url::isValid()
|
|
{
|
|
return url.isValid() && url.hasHost() && !url.protocol().isEmpty();
|
|
}
|
|
|
|
void KGetMetalink::Url::clear()
|
|
{
|
|
priority = 0;
|
|
location.clear();
|
|
url.clear();
|
|
}
|
|
|
|
void KGetMetalink::Resources::load(const QDomElement &e)
|
|
{
|
|
for (QDomElement elem = e.firstChildElement("url"); !elem.isNull(); elem = elem.nextSiblingElement("url"))
|
|
{
|
|
Url url;
|
|
url.load(elem);
|
|
if (url.isValid())
|
|
{
|
|
urls.append(url);
|
|
}
|
|
}
|
|
|
|
for (QDomElement elem = e.firstChildElement("metaurl"); !elem.isNull(); elem = elem.nextSiblingElement("metaurl"))
|
|
{
|
|
Metaurl metaurl;
|
|
metaurl.load(elem);
|
|
if (metaurl.isValid())
|
|
{
|
|
metaurls.append(metaurl);
|
|
}
|
|
}
|
|
}
|
|
|
|
void KGetMetalink::Resources::save(QDomElement &e) const
|
|
{
|
|
foreach (const Metaurl &metaurl, metaurls)
|
|
{
|
|
metaurl.save(e);
|
|
}
|
|
|
|
foreach (const Url &url, urls)
|
|
{
|
|
url.save(e);
|
|
}
|
|
}
|
|
|
|
void KGetMetalink::Resources::clear()
|
|
{
|
|
urls.clear();
|
|
metaurls.clear();
|
|
}
|
|
|
|
void KGetMetalink::Pieces::load(const QDomElement &e)
|
|
{
|
|
type = addaptHashType(e.attribute("type"), true);
|
|
length = e.attribute("length").toULongLong();
|
|
|
|
QDomNodeList hashesList = e.elementsByTagName("hash");
|
|
|
|
for (int i = 0; i < hashesList.count(); ++i)
|
|
{
|
|
QDomElement element = hashesList.at(i).toElement();
|
|
hashes.append(element.text());
|
|
}
|
|
}
|
|
|
|
void KGetMetalink::Pieces::save(QDomElement &e) const
|
|
{
|
|
QDomDocument doc = e.ownerDocument();
|
|
QDomElement pieces = doc.createElement("pieces");
|
|
pieces.setAttribute("type", addaptHashType(type, false));
|
|
pieces.setAttribute("length", length);
|
|
|
|
for (int i = 0; i < hashes.size(); ++i)
|
|
{
|
|
QDomElement hash = doc.createElement("hash");
|
|
QDomText text = doc.createTextNode(hashes.at(i));
|
|
hash.appendChild(text);
|
|
pieces.appendChild(hash);
|
|
}
|
|
|
|
e.appendChild(pieces);
|
|
}
|
|
|
|
void KGetMetalink::Pieces::clear()
|
|
{
|
|
type.clear();
|
|
length = 0;
|
|
hashes.clear();
|
|
}
|
|
|
|
void KGetMetalink::Verification::load(const QDomElement &e)
|
|
{
|
|
for (QDomElement elem = e.firstChildElement("hash"); !elem.isNull(); elem = elem.nextSiblingElement("hash")) {
|
|
QString type = elem.attribute("type");
|
|
const QString hash = elem.text();
|
|
if (!type.isEmpty() && !hash.isEmpty()) {
|
|
type = addaptHashType(type, true);
|
|
hashes[type] = hash;
|
|
}
|
|
}
|
|
|
|
for (QDomElement elem = e.firstChildElement("pieces"); !elem.isNull(); elem = elem.nextSiblingElement("pieces")) {
|
|
Pieces piecesItem;
|
|
piecesItem.load(elem);
|
|
pieces.append(piecesItem);
|
|
}
|
|
|
|
for (QDomElement elem = e.firstChildElement("signature"); !elem.isNull(); elem = elem.nextSiblingElement("signature")) {
|
|
QString type = elem.attribute("mediatype");
|
|
if (type == "application/pgp-signature") {//FIXME with 4.5 make it handle signatures by default with mime-type
|
|
type = "pgp";
|
|
}
|
|
const QString siganture = elem.text();
|
|
if (!type.isEmpty() && !siganture.isEmpty()) {
|
|
signatures[type] = siganture;
|
|
}
|
|
}
|
|
}
|
|
|
|
void KGetMetalink::Verification::save(QDomElement &e) const
|
|
{
|
|
QDomDocument doc = e.ownerDocument();
|
|
|
|
QHash<QString, QString>::const_iterator it;
|
|
QHash<QString, QString>::const_iterator itEnd = hashes.constEnd();
|
|
for (it = hashes.constBegin(); it != itEnd; ++it) {
|
|
QDomElement hash = doc.createElement("hash");
|
|
hash.setAttribute("type", addaptHashType(it.key(), false));
|
|
QDomText text = doc.createTextNode(it.value());
|
|
hash.appendChild(text);
|
|
e.appendChild(hash);
|
|
}
|
|
|
|
foreach (const Pieces &item, pieces) {
|
|
item.save(e);
|
|
}
|
|
|
|
itEnd = signatures.constEnd();
|
|
for (it = signatures.constBegin(); it != itEnd; ++it) {
|
|
QString type = it.key();
|
|
if (type == "pgp") {//FIXME with 4.5 make it handle signatures by default with mime-type
|
|
type = "application/pgp-signature";
|
|
}
|
|
QDomElement hash = doc.createElement("signature");
|
|
hash.setAttribute("mediatype", type);
|
|
QDomText text = doc.createTextNode(it.value());
|
|
hash.appendChild(text);
|
|
e.appendChild(hash);
|
|
}
|
|
}
|
|
|
|
void KGetMetalink::Verification::clear()
|
|
{
|
|
hashes.clear();
|
|
pieces.clear();
|
|
}
|
|
|
|
bool KGetMetalink::File::isValid() const
|
|
{
|
|
return isValidNameAttribute() && resources.isValid();
|
|
}
|
|
|
|
void KGetMetalink::File::load(const QDomElement &e)
|
|
{
|
|
data.load(e);
|
|
|
|
name = QUrl::fromPercentEncoding(e.attribute("name").toAscii());
|
|
size = e.firstChildElement("size").text().toULongLong();
|
|
|
|
verification.load(e);
|
|
resources.load(e);
|
|
}
|
|
|
|
void KGetMetalink::File::save(QDomElement &e) const
|
|
{
|
|
if (isValid())
|
|
{
|
|
QDomDocument doc = e.ownerDocument();
|
|
QDomElement file = doc.createElement("file");
|
|
file.setAttribute("name", name);
|
|
|
|
if (size)
|
|
{
|
|
QDomElement elem = doc.createElement("size");
|
|
QDomText text = doc.createTextNode(QString::number(size));
|
|
elem.appendChild(text);
|
|
file.appendChild(elem);
|
|
}
|
|
|
|
data.save(file);
|
|
resources.save(file);
|
|
verification.save(file);
|
|
|
|
e.appendChild(file);
|
|
}
|
|
}
|
|
|
|
void KGetMetalink::File::clear()
|
|
{
|
|
name.clear();
|
|
verification.clear();
|
|
size = 0;
|
|
data.clear();
|
|
resources.clear();
|
|
}
|
|
|
|
|
|
bool KGetMetalink::File::isValidNameAttribute() const
|
|
{
|
|
if (name.isEmpty()) {
|
|
kError(5001) << "Name attribute of Metalink::File is empty.";
|
|
return false;
|
|
}
|
|
|
|
if (name.endsWith('/')) {
|
|
kError(5001) << "Name attribute of Metalink::File does not contain a file name:" << name;
|
|
return false;
|
|
}
|
|
|
|
const QStringList components = name.split('/');
|
|
if (name.startsWith('/') || components.contains("..") || components.contains(".")) {
|
|
kError(5001) << "Name attribute of Metalink::File contains directory traversal directives:" << name;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool KGetMetalink::Files::isValid() const
|
|
{
|
|
if (files.isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
QStringList fileNames;
|
|
foreach (const File &file, files) {
|
|
fileNames << file.name;
|
|
if (!file.isValid()) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//The value of name must be unique for each file
|
|
while (!fileNames.isEmpty()) {
|
|
const QString fileName = fileNames.takeFirst();
|
|
if (fileNames.contains(fileName)) {
|
|
kError(5001) << "Metalink::File name" << fileName << "exists multiple times.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void KGetMetalink::Files::load(const QDomElement &e)
|
|
{
|
|
for (QDomElement elem = e.firstChildElement("file"); !elem.isNull(); elem = elem.nextSiblingElement("file"))
|
|
{
|
|
File file;
|
|
file.load(elem);
|
|
files.append(file);
|
|
}
|
|
}
|
|
|
|
void KGetMetalink::Files::save(QDomElement &e) const
|
|
{
|
|
if (e.isNull())
|
|
{
|
|
return;
|
|
}
|
|
|
|
foreach (const File &file, files)
|
|
{
|
|
file.save(e);
|
|
}
|
|
}
|
|
|
|
void KGetMetalink::Files::clear()
|
|
{
|
|
files.clear();
|
|
}
|
|
|
|
bool KGetMetalink::Metalink::isValid() const
|
|
{
|
|
return files.isValid();
|
|
}
|
|
|
|
// #ifdef HAVE_NEPOMUK
|
|
// QHash<QUrl, Nepomuk::Variant> KGetMetalink::Files::properties() const
|
|
// {
|
|
// return data.properties();
|
|
// }
|
|
// #endif //HAVE_NEPOMUK
|
|
|
|
void KGetMetalink::Metalink::load(const QDomElement &e)
|
|
{
|
|
QDomDocument doc = e.ownerDocument();
|
|
const QDomElement metalink = doc.firstChildElement("metalink");
|
|
|
|
xmlns = metalink.attribute("xmlns");
|
|
generator = metalink.firstChildElement("generator").text();
|
|
updated.setData(metalink.firstChildElement("updated").text());
|
|
published.setData(metalink.firstChildElement("published").text());
|
|
updated.setData(metalink.firstChildElement("updated").text());
|
|
const QDomElement originElem = metalink.firstChildElement("origin");
|
|
origin = KUrl(metalink.firstChildElement("origin").text());
|
|
if (originElem.hasAttribute("dynamic")) {
|
|
bool worked = false;
|
|
dynamic = originElem.attribute("dynamic").toInt(&worked);
|
|
if (!worked) {
|
|
dynamic = (originElem.attribute("dynamic") == "true");
|
|
}
|
|
}
|
|
|
|
files.load(e);
|
|
}
|
|
|
|
QDomDocument KGetMetalink::Metalink::save() const
|
|
{
|
|
QDomDocument doc;
|
|
QDomProcessingInstruction header = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
|
|
doc.appendChild(header);
|
|
|
|
QDomElement metalink = doc.createElement("metalink");
|
|
metalink.setAttribute("xmlns", "urn:ietf:params:xml:ns:metalink"); //the xmlns value is ignored, instead the data format described in the specification is always used
|
|
|
|
QDomElement elem = doc.createElement("generator");
|
|
QDomText text = doc.createTextNode(Metalink::KGET_DESCRIPTION); //the set generator is ignored, instead when saving KGET is always used
|
|
elem.appendChild(text);
|
|
metalink.appendChild(elem);
|
|
|
|
if (!origin.isEmpty()) {
|
|
QDomElement elem = doc.createElement("origin");
|
|
QDomText text = doc.createTextNode(origin.url());
|
|
elem.appendChild(text);
|
|
if (dynamic) {
|
|
elem.setAttribute("dynamic", "true");
|
|
}
|
|
metalink.appendChild(elem);
|
|
}
|
|
if (published.isValid()) {
|
|
QDomElement elem = doc.createElement("published");
|
|
QDomText text = doc.createTextNode(published.toString());
|
|
elem.appendChild(text);
|
|
metalink.appendChild(elem);
|
|
}
|
|
if (updated.isValid()) {
|
|
QDomElement elem = doc.createElement("updated");
|
|
QDomText text = doc.createTextNode(updated.toString());
|
|
elem.appendChild(text);
|
|
metalink.appendChild(elem);
|
|
}
|
|
|
|
files.save(metalink);
|
|
|
|
doc.appendChild(metalink);
|
|
|
|
return doc;
|
|
}
|
|
|
|
void KGetMetalink::Metalink::clear()
|
|
{
|
|
dynamic = false;
|
|
xmlns.clear();
|
|
published.clear();
|
|
origin.clear();
|
|
generator.clear();
|
|
updated.clear();
|
|
files.clear();
|
|
}
|
|
|
|
KGetMetalink::Metalink_v3::Metalink_v3()
|
|
{
|
|
}
|
|
|
|
KGetMetalink::Metalink KGetMetalink::Metalink_v3::metalink()
|
|
{
|
|
return m_metalink;
|
|
}
|
|
|
|
void KGetMetalink::Metalink_v3::setMetalink(const KGetMetalink::Metalink &metalink)
|
|
{
|
|
m_metalink = metalink;
|
|
}
|
|
|
|
void KGetMetalink::Metalink_v3::load(const QDomElement &e)
|
|
{
|
|
QDomDocument doc = e.ownerDocument();
|
|
const QDomElement metalinkDom = doc.firstChildElement("metalink");
|
|
|
|
m_metalink.dynamic = (metalinkDom.attribute("type") == "dynamic");
|
|
m_metalink.origin = KUrl(metalinkDom.attribute("origin"));
|
|
m_metalink.generator = metalinkDom.attribute("generator");
|
|
m_metalink.published = parseDateConstruct(metalinkDom.attribute("pubdate"));
|
|
m_metalink.updated = parseDateConstruct(metalinkDom.attribute("refreshdate"));
|
|
|
|
parseFiles(metalinkDom);
|
|
}
|
|
|
|
void KGetMetalink::Metalink_v3::parseFiles(const QDomElement &e)
|
|
{
|
|
//here we assume that the CommonData set in metalink is for every file in the metalink
|
|
CommonData data;
|
|
data = parseCommonData(e);
|
|
|
|
const QDomElement filesElem = e.firstChildElement("files");
|
|
CommonData filesData = parseCommonData(filesElem);
|
|
|
|
inheritCommonData(data, &filesData);
|
|
|
|
for (QDomElement elem = filesElem.firstChildElement("file"); !elem.isNull(); elem = elem.nextSiblingElement("file")) {
|
|
File file;
|
|
file.name = QUrl::fromPercentEncoding(elem.attribute("name").toAscii());
|
|
file.size = elem.firstChildElement("size").text().toULongLong();
|
|
|
|
file.data = parseCommonData(elem);
|
|
inheritCommonData(filesData, &file.data);
|
|
|
|
file.resources = parseResources(elem);
|
|
|
|
//load the verification information
|
|
QDomElement veriE = elem.firstChildElement("verification");
|
|
|
|
for (QDomElement elemVer = veriE.firstChildElement("hash"); !elemVer.isNull(); elemVer = elemVer.nextSiblingElement("hash")) {
|
|
QString type = elemVer.attribute("type");
|
|
QString hash = elemVer.text();
|
|
if (!type.isEmpty() && !hash.isEmpty()) {
|
|
type = addaptHashType(type, true);
|
|
file.verification.hashes[type] = hash;
|
|
}
|
|
}
|
|
|
|
for (QDomElement elemVer = veriE.firstChildElement("pieces"); !elemVer.isNull(); elemVer = elemVer.nextSiblingElement("pieces")) {
|
|
Pieces piecesItem;
|
|
piecesItem.load(elemVer);
|
|
file.verification.pieces.append(piecesItem);
|
|
}
|
|
|
|
for (QDomElement elemVer = veriE.firstChildElement("signature"); !elemVer.isNull(); elemVer = elemVer.nextSiblingElement("signature")) {
|
|
const QString type = elemVer.attribute("type");
|
|
const QString signature = elemVer.text();
|
|
if (!type.isEmpty() && !signature.isEmpty()) {
|
|
file.verification.signatures[type] = signature;
|
|
}
|
|
}
|
|
|
|
m_metalink.files.files.append(file);
|
|
}
|
|
}
|
|
|
|
KGetMetalink::CommonData KGetMetalink::Metalink_v3::parseCommonData(const QDomElement &e)
|
|
{
|
|
CommonData data;
|
|
|
|
data.load(e);
|
|
|
|
const QDomElement publisherElem = e.firstChildElement("publisher");
|
|
data.publisher.name = publisherElem.firstChildElement("name").text();
|
|
data.publisher.url = KUrl(publisherElem.firstChildElement("url").text());
|
|
|
|
return data;
|
|
}
|
|
|
|
void KGetMetalink::Metalink_v3::inheritCommonData(const KGetMetalink::CommonData &ancestor, KGetMetalink::CommonData *inheritor)
|
|
{
|
|
if (!inheritor) {
|
|
return;
|
|
}
|
|
|
|
//ensure that inheritance works
|
|
if (inheritor->identity.isEmpty()) {
|
|
inheritor->identity = ancestor.identity;
|
|
}
|
|
if (inheritor->version.isEmpty()) {
|
|
inheritor->version = ancestor.version;
|
|
}
|
|
if (inheritor->description.isEmpty()) {
|
|
inheritor->description = ancestor.description;
|
|
}
|
|
if (inheritor->oses.isEmpty()) {
|
|
inheritor->oses = ancestor.oses;
|
|
}
|
|
if (inheritor->logo.isEmpty()) {
|
|
inheritor->logo = ancestor.logo;
|
|
}
|
|
if (inheritor->languages.isEmpty()) {
|
|
inheritor->languages = ancestor.languages;
|
|
}
|
|
if (inheritor->copyright.isEmpty()) {
|
|
inheritor->copyright = ancestor.copyright;
|
|
}
|
|
if (inheritor->publisher.isEmpty()) {
|
|
inheritor->publisher = ancestor.publisher;
|
|
}
|
|
}
|
|
|
|
KGetMetalink::Resources KGetMetalink::Metalink_v3::parseResources(const QDomElement &e)
|
|
{
|
|
Resources resources;
|
|
|
|
QDomElement res = e.firstChildElement("resources");
|
|
for (QDomElement elemRes = res.firstChildElement("url"); !elemRes.isNull(); elemRes = elemRes.nextSiblingElement("url")) {
|
|
const QString location = elemRes.attribute("location").toLower();
|
|
|
|
uint preference = elemRes.attribute("preference").toUInt();
|
|
//the maximum preference we use is MAX_PREFERENCE
|
|
if (preference > MAX_PREFERENCE) {
|
|
preference = MAX_PREFERENCE;
|
|
}
|
|
const int priority = MAX_PREFERENCE - preference + 1;//convert old preference to new priority
|
|
|
|
const KUrl link = KUrl(elemRes.text());
|
|
QString type;
|
|
|
|
if (link.fileName().endsWith(QLatin1String(".torrent"))) {
|
|
type = "torrent";
|
|
}
|
|
|
|
if (type.isEmpty()) {
|
|
Url url;
|
|
if (preference) {
|
|
url.priority = priority;
|
|
}
|
|
url.location = location;
|
|
url.url = link;
|
|
if (url.isValid()) {
|
|
resources.urls.append(url);
|
|
}
|
|
} else {
|
|
//it might be a metaurl
|
|
Metaurl metaurl;
|
|
if (preference) {
|
|
metaurl.priority = priority;
|
|
}
|
|
metaurl.url = link;
|
|
metaurl.type = type;
|
|
if (metaurl.isValid()) {
|
|
resources.metaurls.append(metaurl);
|
|
}
|
|
}
|
|
}
|
|
|
|
return resources;
|
|
}
|
|
|
|
KGetMetalink::DateConstruct KGetMetalink::Metalink_v3::parseDateConstruct(const QString &data)
|
|
{
|
|
DateConstruct dateConstruct;
|
|
|
|
if (data.isEmpty()){
|
|
return dateConstruct;
|
|
}
|
|
|
|
kDebug(5001) << "Parsing" << data;
|
|
|
|
QString temp = data;
|
|
QDateTime dateTime;
|
|
QTime timeZoneOffset;
|
|
|
|
//Date according to RFC 822, the year with four characters preferred
|
|
//e.g.: "Mon, 15 May 2006 00:00:01 GMT", "Fri, 01 Apr 2009 00:00:01 +1030"
|
|
|
|
//find the date
|
|
const QString weekdayExp = "ddd, ";
|
|
const bool weekdayIncluded = (temp.indexOf(',') == 3);
|
|
int startPosition = (weekdayIncluded ? weekdayExp.length() : 0);
|
|
const QString dayMonthExp = "dd MMM ";
|
|
const QString yearExp = "yy";
|
|
|
|
QString exp = dayMonthExp + yearExp + yearExp;
|
|
int length = exp.length();
|
|
|
|
QLocale locale = QLocale::c();
|
|
QDate date = locale.toDate(temp.mid(startPosition, length), exp);
|
|
if (!date.isValid()) {
|
|
exp = dayMonthExp + yearExp;
|
|
length = exp.length();
|
|
date = locale.toDate(temp.mid(startPosition, length), exp);
|
|
if (!date.isValid()) {
|
|
return dateConstruct;
|
|
}
|
|
}
|
|
|
|
//find the time
|
|
dateTime.setDate(date);
|
|
temp = temp.mid(startPosition);
|
|
temp = temp.mid(length + 1);//also remove the space
|
|
|
|
const QString hourExp = "hh";
|
|
const QString minuteExp = "mm";
|
|
const QString secondExp = "ss";
|
|
|
|
exp = hourExp + ':' + minuteExp + ':' + secondExp;
|
|
length = exp.length();
|
|
QTime time = QTime::fromString(temp.left(length), exp);
|
|
if (!time.isValid()) {
|
|
exp = hourExp + ':' + minuteExp;
|
|
length = exp.length();
|
|
time = QTime::fromString(temp.left(length), exp);
|
|
if (!time.isValid()) {
|
|
return dateConstruct;
|
|
}
|
|
}
|
|
dateTime.setTime(time);
|
|
|
|
//find the offset
|
|
temp = temp.mid(length + 1);//also remove the space
|
|
bool negativeOffset = false;
|
|
|
|
if (temp.length() == 3) { //e.g. GMT
|
|
KTimeZone timeZone = KSystemTimeZones::readZone(temp);
|
|
if (timeZone.isValid()) {
|
|
int offset = timeZone.currentOffset();
|
|
negativeOffset = (offset < 0);
|
|
timeZoneOffset = QTime(0, 0, 0);
|
|
timeZoneOffset = timeZoneOffset.addSecs(qAbs(offset));
|
|
}
|
|
} else if (temp.length() == 5) { //e.g. +1030
|
|
negativeOffset = (temp[0] == '-');
|
|
timeZoneOffset = QTime::fromString(temp.mid(1,4), "hhmm");
|
|
}
|
|
|
|
dateConstruct.setData(dateTime, timeZoneOffset, negativeOffset);
|
|
|
|
return dateConstruct;
|
|
}
|
|
|
|
QDomDocument KGetMetalink::Metalink_v3::save() const
|
|
{
|
|
QDomDocument doc;
|
|
QDomProcessingInstruction header = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
|
|
doc.appendChild(header);
|
|
|
|
QDomElement metalink = doc.createElement("metalink");
|
|
metalink.setAttribute("xmlns", "http://www.metalinker.org/");
|
|
metalink.setAttribute("version", "3.0");
|
|
metalink.setAttribute("type", (m_metalink.dynamic ? "dynamic" : "static"));
|
|
metalink.setAttribute("generator", Metalink::KGET_DESCRIPTION); //the set generator is ignored, instead when saving KGET is always used
|
|
|
|
if (m_metalink.published.isValid()) {
|
|
metalink.setAttribute("pubdate", dateConstructToString(m_metalink.published));
|
|
}
|
|
if (m_metalink.updated.isValid()) {
|
|
metalink.setAttribute("refreshdate", dateConstructToString(m_metalink.updated));
|
|
}
|
|
if (!m_metalink.origin.isEmpty()) {
|
|
metalink.setAttribute("origin", m_metalink.origin.url());
|
|
}
|
|
|
|
saveFiles(metalink);
|
|
|
|
doc.appendChild(metalink);
|
|
|
|
return doc;
|
|
}
|
|
|
|
void KGetMetalink::Metalink_v3::saveFiles(QDomElement &e) const
|
|
{
|
|
QDomDocument doc = e.ownerDocument();
|
|
QDomElement filesElem = doc.createElement("files");
|
|
|
|
foreach (const File &file, m_metalink.files.files) {
|
|
QDomElement elem = doc.createElement("file");
|
|
elem.setAttribute("name", file.name);
|
|
|
|
QDomElement size = doc.createElement("size");
|
|
QDomText text = doc.createTextNode(QString::number(file.size));
|
|
size.appendChild(text);
|
|
elem.appendChild(size);
|
|
|
|
saveCommonData(file.data, elem);
|
|
saveResources(file.resources, elem);
|
|
saveVerification(file.verification, elem);
|
|
|
|
filesElem.appendChild(elem);
|
|
}
|
|
|
|
e.appendChild(filesElem);
|
|
}
|
|
|
|
void KGetMetalink::Metalink_v3::saveResources(const Resources &resources, QDomElement &e) const
|
|
{
|
|
QDomDocument doc = e.ownerDocument();
|
|
QDomElement res = doc.createElement("resources");
|
|
|
|
foreach (const Url &url, resources.urls) {
|
|
QDomElement elem = doc.createElement("url");
|
|
const uint priority = url.priority;
|
|
if (priority) {
|
|
int preference = MAX_PREFERENCE - priority + 1;
|
|
if (preference <= 0) {
|
|
preference = 1;//HACK if priority is larger MAX_PREFERENCE makes it 1
|
|
}
|
|
elem.setAttribute("preference", preference);
|
|
}
|
|
if (!url.location.isEmpty()) {
|
|
elem.setAttribute("location", url.location);
|
|
}
|
|
|
|
QDomText text = doc.createTextNode(url.url.url());
|
|
elem.appendChild(text);
|
|
|
|
res.appendChild(elem);
|
|
}
|
|
|
|
foreach (const Metaurl &metaurl, resources.metaurls) {
|
|
if (metaurl.type == "torrent") {
|
|
QDomElement elem = doc.createElement("url");
|
|
elem.setAttribute("type", "bittorrent");
|
|
const uint priority = metaurl.priority;
|
|
if (priority) {
|
|
int preference = MAX_PREFERENCE - priority + 1;
|
|
if (preference <= 0) {
|
|
preference = 1;//HACK if priority is larger MAX_PREFERENCE makes it 1
|
|
}
|
|
elem.setAttribute("preference", preference);
|
|
}
|
|
|
|
QDomText text = doc.createTextNode(metaurl.url.url());
|
|
elem.appendChild(text);
|
|
|
|
res.appendChild(elem);
|
|
}
|
|
}
|
|
|
|
e.appendChild(res);
|
|
}
|
|
|
|
void KGetMetalink::Metalink_v3::saveVerification(const KGetMetalink::Verification &verification, QDomElement &e) const
|
|
{
|
|
QDomDocument doc = e.ownerDocument();
|
|
QDomElement veri = doc.createElement("verification");
|
|
|
|
QHash<QString, QString>::const_iterator it;
|
|
QHash<QString, QString>::const_iterator itEnd = verification.hashes.constEnd();
|
|
for (it = verification.hashes.constBegin(); it != itEnd; ++it) {
|
|
QDomElement elem = doc.createElement("hash");
|
|
elem.setAttribute("type", it.key());
|
|
QDomText text = doc.createTextNode(it.value());
|
|
elem.appendChild(text);
|
|
|
|
veri.appendChild(elem);
|
|
}
|
|
|
|
foreach (const Pieces &pieces, verification.pieces) {
|
|
QDomElement elem = doc.createElement("pieces");
|
|
elem.setAttribute("type", pieces.type);
|
|
elem.setAttribute("length", QString::number(pieces.length));
|
|
|
|
for (int i = 0; i < pieces.hashes.count(); ++i) {
|
|
QDomElement hash = doc.createElement("hash");
|
|
hash.setAttribute("piece", i);
|
|
QDomText text = doc.createTextNode(pieces.hashes.at(i));
|
|
hash.appendChild(text);
|
|
|
|
elem.appendChild(hash);
|
|
}
|
|
veri.appendChild(elem);
|
|
}
|
|
|
|
itEnd = verification.signatures.constEnd();
|
|
for (it = verification.signatures.constBegin(); it != itEnd; ++it) {
|
|
QDomElement elem = doc.createElement("signature");
|
|
elem.setAttribute("type", it.key());
|
|
QDomText text = doc.createTextNode(it.value());
|
|
elem.appendChild(text);
|
|
|
|
veri.appendChild(elem);
|
|
}
|
|
|
|
e.appendChild(veri);
|
|
}
|
|
|
|
void KGetMetalink::Metalink_v3::saveCommonData(const KGetMetalink::CommonData &data, QDomElement &e) const
|
|
{
|
|
QDomDocument doc = e.ownerDocument();
|
|
|
|
CommonData commonData = data;
|
|
|
|
if (!commonData.publisher.isEmpty()) {
|
|
QDomElement elem = doc.createElement("publisher");
|
|
QDomElement elemName = doc.createElement("name");
|
|
QDomElement elemUrl = doc.createElement("url");
|
|
|
|
QDomText text = doc.createTextNode(commonData.publisher.name);
|
|
elemName.appendChild(text);
|
|
elem.appendChild(elemName);
|
|
|
|
text = doc.createTextNode(commonData.publisher.url.url());
|
|
elemUrl.appendChild(text);
|
|
elem.appendChild(elemUrl);
|
|
|
|
e.appendChild(elem);
|
|
|
|
commonData.publisher.clear();
|
|
}
|
|
|
|
if (commonData.oses.count() > 1) {//only one OS can be set in 3.0
|
|
commonData.oses.clear();
|
|
}
|
|
|
|
commonData.save(e);
|
|
}
|
|
|
|
QString KGetMetalink::Metalink_v3::dateConstructToString(const KGetMetalink::DateConstruct &date) const
|
|
{
|
|
QString dateString;
|
|
if (!date.isValid()) {
|
|
return dateString;
|
|
}
|
|
|
|
QLocale locale = QLocale::c();
|
|
|
|
//"Fri, 01 Apr 2009 00:00:01 +1030"
|
|
dateString += locale.toString(date.dateTime, "ddd, dd MMM yyyy hh:mm:ss ");
|
|
|
|
if (date.timeZoneOffset.isValid()) {
|
|
dateString += (date.negativeOffset ? '-' : '+');
|
|
dateString += date.timeZoneOffset.toString("hhmm");
|
|
} else {
|
|
dateString += "+0000";
|
|
}
|
|
|
|
return dateString;
|
|
}
|
|
|
|
|
|
bool KGetMetalink::HandleMetalink::load(const KUrl &destination, KGetMetalink::Metalink *metalink)
|
|
{
|
|
QFile file(destination.pathOrUrl());
|
|
if (!file.open(QIODevice::ReadOnly))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
QDomDocument doc;
|
|
if (!doc.setContent(&file))
|
|
{
|
|
file.close();
|
|
return false;
|
|
}
|
|
file.close();
|
|
|
|
QDomElement root = doc.documentElement();
|
|
if (root.attribute("xmlns") == "urn:ietf:params:xml:ns:metalink")
|
|
{
|
|
metalink->load(root);
|
|
return true;
|
|
}
|
|
else if ((root.attribute("xmlns") == "http://www.metalinker.org/") || (root.attribute("version") == "3.0"))
|
|
{
|
|
Metalink_v3 metalink_v3;
|
|
metalink_v3.load(root);
|
|
*metalink = metalink_v3.metalink();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool KGetMetalink::HandleMetalink::load(const QByteArray &data, KGetMetalink::Metalink *metalink)
|
|
{
|
|
if (data.isNull())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
QDomDocument doc;
|
|
if (!doc.setContent(data))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
metalink->clear();
|
|
QDomElement root = doc.documentElement();
|
|
if (root.attribute("xmlns") == "urn:ietf:params:xml:ns:metalink")
|
|
{
|
|
metalink->load(root);
|
|
return true;
|
|
}
|
|
else if ((root.attribute("xmlns") == "http://www.metalinker.org/") || (root.attribute("version") == "3.0"))
|
|
{
|
|
Metalink_v3 metalink_v3;
|
|
metalink_v3.load(root);
|
|
*metalink = metalink_v3.metalink();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool KGetMetalink::HandleMetalink::save(const KUrl &destination, KGetMetalink::Metalink *metalink)
|
|
{
|
|
QFile file(destination.pathOrUrl());
|
|
if (!file.open(QIODevice::WriteOnly)) {
|
|
return false;
|
|
}
|
|
|
|
QDomDocument doc;
|
|
QString fileName = destination.fileName();
|
|
if (fileName.endsWith(QLatin1String("meta4"))) {
|
|
doc = metalink->save();
|
|
} else if (fileName.endsWith(QLatin1String("metalink"))) {
|
|
Metalink_v3 metalink_v3;
|
|
metalink_v3.setMetalink(*metalink);
|
|
doc = metalink_v3.save();
|
|
} else {
|
|
file.close();
|
|
return false;
|
|
}
|
|
|
|
QTextStream stream(&file);
|
|
doc.save(stream, 2);
|
|
file.close();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
KGetMetalink::MetalinkHttpParser::~MetalinkHttpParser()
|
|
{
|
|
|
|
}
|
|
|
|
QString* KGetMetalink::MetalinkHttpParser::getEtag()
|
|
{
|
|
return &m_EtagValue;
|
|
}
|
|
|
|
void KGetMetalink::MetalinkHttpParser::checkMetalinkHttp()
|
|
{
|
|
if (!m_Url.isValid()) {
|
|
kDebug() << "Url not valid";
|
|
return;
|
|
}
|
|
|
|
KIO::TransferJob *job;
|
|
job = KIO::get(m_Url, KIO::NoReload, KIO::HideProgressInfo);
|
|
job->addMetaData("PropagateHttpHeader", "true");
|
|
job->setRedirectionHandlingEnabled(false);
|
|
connect(job, SIGNAL(result(KJob*)), this, SLOT(slotHeaderResult(KJob*))); // Finished
|
|
connect(job, SIGNAL(redirection(KIO::Job*,KUrl)), this, SLOT(slotRedirection(KIO::Job*,KUrl))); // Redirection
|
|
connect(job,SIGNAL(mimetype(KIO::Job*,QString)),this,SLOT(detectMime(KIO::Job*,QString))); // Mime detection.
|
|
kDebug() << " Verifying Metalink/HTTP Status" ;
|
|
m_loop.exec();
|
|
}
|
|
|
|
void KGetMetalink::MetalinkHttpParser::detectMime(KIO::Job *job, const QString &type)
|
|
{
|
|
kDebug() << "Mime Type: " << type ;
|
|
job->kill();
|
|
m_loop.exit();
|
|
}
|
|
|
|
void KGetMetalink::MetalinkHttpParser::slotHeaderResult(KJob* kjob)
|
|
{
|
|
KIO::Job* job = qobject_cast<KIO::Job*>(kjob);
|
|
const QString httpHeaders = job ? job->queryMetaData("HTTP-Headers") : QString();
|
|
parseHeaders(httpHeaders);
|
|
setMetalinkHSatus();
|
|
|
|
// Handle the redirection... (Comment out if not desired)
|
|
if (m_redirectionUrl.isValid()) {
|
|
m_Url = m_redirectionUrl;
|
|
m_redirectionUrl = KUrl();
|
|
checkMetalinkHttp();
|
|
}
|
|
|
|
if (m_loop.isRunning())
|
|
m_loop.exit();
|
|
}
|
|
|
|
void KGetMetalink::MetalinkHttpParser::slotRedirection(KIO::Job *job, const KUrl & url)
|
|
{
|
|
Q_UNUSED(job)
|
|
m_redirectionUrl = url;
|
|
}
|
|
|
|
bool KGetMetalink::MetalinkHttpParser::isMetalinkHttp()
|
|
{
|
|
if (m_MetalinkHSatus) {
|
|
kDebug() << "Metalink Http detected" ;
|
|
}
|
|
else {
|
|
kDebug() << "No Metalink HTTP response found" ;
|
|
}
|
|
return m_MetalinkHSatus;
|
|
}
|
|
|
|
void KGetMetalink::MetalinkHttpParser::parseHeaders(const QString &httpHeader)
|
|
{
|
|
QString trimedHeader = httpHeader.mid(httpHeader.indexOf('\n') + 1).trimmed();
|
|
|
|
foreach(QString line, trimedHeader.split('\n')) {
|
|
int colon = line.indexOf(':');
|
|
QString headerName = line.left(colon).trimmed();
|
|
QString headerValue = line.mid(colon + 1).trimmed();
|
|
m_headerInfo.insertMulti(headerName, headerValue);
|
|
}
|
|
|
|
m_EtagValue = m_headerInfo.value("ETag");
|
|
}
|
|
|
|
void KGetMetalink::MetalinkHttpParser::setMetalinkHSatus()
|
|
{
|
|
bool linkStatus, digestStatus;
|
|
linkStatus = digestStatus = false;
|
|
if (m_headerInfo.contains("link")) {
|
|
QList<QString> linkValues = m_headerInfo.values("link");
|
|
|
|
foreach(QString linkVal, linkValues) {
|
|
if (linkVal.contains("rel=duplicate")) {
|
|
linkStatus = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_headerInfo.contains("digest")) {
|
|
QList<QString> digestValues = m_headerInfo.values("digest");
|
|
|
|
foreach(QString digestVal, digestValues) {
|
|
if (digestVal.contains("sha-256", Qt::CaseInsensitive)) {
|
|
digestStatus = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((linkStatus) && (digestStatus)) {
|
|
m_MetalinkHSatus = true;
|
|
}
|
|
|
|
}
|
|
|
|
KUrl KGetMetalink::MetalinkHttpParser::getUrl()
|
|
{
|
|
return m_Url;
|
|
}
|
|
|
|
QMultiMap<QString, QString>* KGetMetalink::MetalinkHttpParser::getHeaderInfo()
|
|
{
|
|
return & m_headerInfo;
|
|
}
|
|
|
|
KGetMetalink::HttpLinkHeader::HttpLinkHeader(const QString &headerLine)
|
|
: pref(false)
|
|
{
|
|
parseHeaderLine(headerLine);
|
|
}
|
|
|
|
bool KGetMetalink::HttpLinkHeader::operator<(const HttpLinkHeader &other) const
|
|
{
|
|
return depth < other.depth;
|
|
}
|
|
|
|
void KGetMetalink::HttpLinkHeader::parseHeaderLine(const QString &line)
|
|
{
|
|
url = line.mid(line.indexOf("<") + 1,line.indexOf(">") -1).trimmed();
|
|
const QList<QString> attribList = line.split(";");
|
|
|
|
foreach (const QString str, attribList) {
|
|
const QString attribId = str.mid(0,str.indexOf("=")).trimmed();
|
|
const QString attribValue = str.mid(str.indexOf("=")+1).trimmed();
|
|
|
|
if (attribId == "rel") {
|
|
reltype = attribValue;
|
|
}
|
|
else if (attribId == "depth") {
|
|
depth = attribValue.toInt();
|
|
}
|
|
else if (attribId == "geo") {
|
|
geo = attribValue;
|
|
}
|
|
else if (attribId == "pref") {
|
|
pref = true;
|
|
}
|
|
else if (attribId == "pri") {
|
|
priority = attribValue.toUInt();
|
|
}
|
|
else if (attribId == "type") {
|
|
type = attribValue;
|
|
}
|
|
else if (attribId == "name") {
|
|
name = attribValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
#include "metalinker.moc"
|