23 #include <QtCore/QFile>
24 #include <QtCore/QTextStream>
25 #include <QtXml/QDomElement>
27 #include <kdeversion.h>
30 #include <KSystemTimeZone>
33 #include <Nepomuk2/Variant>
34 #include <Nepomuk2/Vocabulary/NCO>
35 #include <Nepomuk2/Vocabulary/NIE>
36 #include <Nepomuk2/Vocabulary/NFO>
37 #include <Soprano/Vocabulary/NAO>
39 using namespace Nepomuk2::Vocabulary;
40 using namespace Soprano::Vocabulary;
45 const uint KGetMetalink::Metalink_v3::MAX_PREFERENCE = 100;
47 namespace KGetMetalink
65 t.replace(
"sha-",
"sha");
69 t.replace(
"sha",
"sha-");
78 timeZoneOffset = timeZoneOff;
79 negativeOffset = negOff;
84 if (dateConstruct.isEmpty())
89 const QString exp =
"yyyy-MM-ddThh:mm:ss";
90 const int length = exp.length();
92 dateTime = QDateTime::fromString(dateConstruct.left(length), exp);
93 if (dateTime.isValid())
95 int index = dateConstruct.indexOf(
'+', length - 1);
98 timeZoneOffset = QTime::fromString(dateConstruct.mid(index + 1),
"hh:mm");
102 index = dateConstruct.indexOf(
'-', length - 1);
105 negativeOffset =
true;
106 timeZoneOffset = QTime::fromString(dateConstruct.mid(index + 1),
"hh:mm");
114 return dateTime.isNull();
119 return dateTime.isValid();
126 if (dateTime.isValid())
128 string += dateTime.toString(Qt::ISODate);
131 if (timeZoneOffset.isValid())
133 string += (negativeOffset ?
'-' :
'+');
134 string += timeZoneOffset.toString(
"hh:mm");
136 else if (!
string.isEmpty())
146 dateTime = QDateTime();
147 timeZoneOffset = QTime();
158 identity = e.firstChildElement(
"identity").text();
159 version = e.firstChildElement(
"version").text();
160 description = e.firstChildElement(
"description").text();
161 logo = KUrl(e.firstChildElement(
"logo").text());
162 copyright = e.firstChildElement(
"copyright").text();
164 const QDomElement publisherElem = e.firstChildElement(
"publisher");
165 publisher.name = publisherElem.attribute(
"name");
166 publisher.url = KUrl(publisherElem.attribute(
"url"));
168 for (QDomElement elemRes = e.firstChildElement(
"language"); !elemRes.isNull(); elemRes = elemRes.nextSiblingElement(
"language")) {
169 languages << elemRes.text();
172 for (QDomElement elemRes = e.firstChildElement(
"os"); !elemRes.isNull(); elemRes = elemRes.nextSiblingElement(
"os")) {
173 oses << elemRes.text();
179 QDomDocument doc = e.ownerDocument();
181 if (!copyright.isEmpty())
183 QDomElement elem = doc.createElement(
"copyright");
184 QDomText text = doc.createTextNode(copyright);
185 elem.appendChild(text);
188 if (!description.isEmpty())
190 QDomElement elem = doc.createElement(
"description");
191 QDomText text = doc.createTextNode(description);
192 elem.appendChild(text);
195 if (!identity.isEmpty())
197 QDomElement elem = doc.createElement(
"identity");
198 QDomText text = doc.createTextNode(identity);
199 elem.appendChild(text);
204 QDomElement elem = doc.createElement(
"logo");
205 QDomText text = doc.createTextNode(logo.url());
206 elem.appendChild(text);
209 if (!publisher.isEmpty())
211 QDomElement elem = doc.createElement(
"publisher");
212 elem.setAttribute(
"url", publisher.url.url());
213 elem.setAttribute(
"name", publisher.name);
217 if (!version.isEmpty())
219 QDomElement elem = doc.createElement(
"version");
220 QDomText text = doc.createTextNode(version);
221 elem.appendChild(text);
225 foreach (
const QString &language, languages) {
226 QDomElement elem = doc.createElement(
"language");
227 QDomText text = doc.createTextNode(language);
228 elem.appendChild(text);
232 foreach (
const QString &os, oses) {
233 QDomElement elem = doc.createElement(
"os");
234 QDomText text = doc.createTextNode(os);
235 elem.appendChild(text);
253 QList<QPair<QUrl, Nepomuk2::Variant> > KGetMetalink::CommonData::properties()
const
256 QList<QPair<QUrl, Nepomuk2::Variant> > data;
258 HandleMetalink::addProperty(&data, NIE::version(), version);
259 HandleMetalink::addProperty(&data, NIE::description(), description);
261 QList<Nepomuk2::Resource> osResources;
262 foreach (
const QString &os, oses) {
263 Nepomuk2::Resource osRes(os, NFO::OperatingSystem());
264 osRes.setProperty(NIE::title(), os);
265 osResources << osRes;
267 if (!osResources.isEmpty()) {
268 data << qMakePair(NAO::isRelated(), Nepomuk2::Variant(osResources));
271 if (!logo.isEmpty()) {
272 Nepomuk2::Resource logoRes(logo, NFO::RemoteDataObject());
273 logoRes.addType(NAO::Symbol());
274 data << qMakePair(NAO::hasSymbol(), Nepomuk2::Variant(logoRes));
277 QList<Nepomuk2::Variant> langVariants;
278 foreach (
const QString &language, languages) {
279 langVariants << language;
281 if (langVariants.count()) {
282 data << qMakePair(NIE::language(), Nepomuk2::Variant(langVariants));
285 if (!publisher.name.isEmpty()) {
286 Nepomuk2::Resource res(publisher.name, NCO::OrganizationContact());
287 res.setLabel(publisher.name);
288 res.addProperty(NCO::fullname(), publisher.name);
289 if (!publisher.url.isEmpty()) {
290 Nepomuk2::Resource website(publisher.url, NFO::Website());
291 website.addProperty(NIE::url(), publisher.url);
292 res.addProperty(NCO::websiteUrl(), website);
294 data << qMakePair(NCO::publisher(), Nepomuk2::Variant(res));
297 HandleMetalink::addProperty(&data, NIE::copyright(), copyright);
301 #endif //HAVE_NEPOMUK
306 return (this->priority > other.
priority) || (this->priority == 0);
311 type = e.attribute(
"mediatype").toLower();
312 priority = e.attribute(
"priority").toUInt();
313 if (priority > Metalink::MAX_URL_PRIORITY) {
314 priority = Metalink::MAX_URL_PRIORITY;
316 name = e.attribute(
"name");
317 url = KUrl(e.text());
322 QDomDocument doc = e.ownerDocument();
323 QDomElement metaurl = doc.createElement(
"metaurl");
326 metaurl.setAttribute(
"priority", priority);
330 metaurl.setAttribute(
"name", name);
332 metaurl.setAttribute(
"mediatype", type);
334 QDomText text = doc.createTextNode(url.url());
335 metaurl.appendChild(text);
337 e.appendChild(metaurl);
342 return url.isValid() && url.hasHost() && !url.protocol().isEmpty() && !type.isEmpty();
355 bool smaller = (this->priority > other.
priority) || ((this->priority == 0) && (other.
priority != 0));
357 if (!smaller && (this->priority == other.
priority)) {
358 QString countryCode = KGlobal::locale()->country();
359 if (!countryCode.isEmpty()) {
360 smaller = (other.
location.toLower() == countryCode.toLower());
368 location = e.attribute(
"location").toLower();
369 priority = e.attribute(
"priority").toUInt();
370 if (priority > Metalink::MAX_URL_PRIORITY) {
371 priority = Metalink::MAX_URL_PRIORITY;
373 url = KUrl(e.text());
378 QDomDocument doc = e.ownerDocument();
379 QDomElement elem = doc.createElement(
"url");
382 elem.setAttribute(
"priority", priority);
384 if (!location.isEmpty())
386 elem.setAttribute(
"location", location);
389 QDomText text = doc.createTextNode(url.url());
390 elem.appendChild(text);
397 return url.isValid() && url.hasHost() && !url.protocol().isEmpty();
409 for (QDomElement elem = e.firstChildElement(
"url"); !elem.isNull(); elem = elem.nextSiblingElement(
"url"))
419 for (QDomElement elem = e.firstChildElement(
"metaurl"); !elem.isNull(); elem = elem.nextSiblingElement(
"metaurl"))
425 metaurls.append(metaurl);
432 foreach (
const Metaurl &metaurl, metaurls)
437 foreach (
const Url &url, urls)
452 length = e.attribute(
"length").toULongLong();
454 QDomNodeList hashesList = e.elementsByTagName(
"hash");
456 for (
int i = 0; i < hashesList.count(); ++i)
458 QDomElement element = hashesList.at(i).toElement();
459 hashes.append(element.text());
465 QDomDocument doc = e.ownerDocument();
466 QDomElement pieces = doc.createElement(
"pieces");
468 pieces.setAttribute(
"length", length);
470 for (
int i = 0; i < hashes.size(); ++i)
472 QDomElement hash = doc.createElement(
"hash");
473 QDomText text = doc.createTextNode(hashes.at(i));
474 hash.appendChild(text);
475 pieces.appendChild(hash);
478 e.appendChild(pieces);
490 for (QDomElement elem = e.firstChildElement(
"hash"); !elem.isNull(); elem = elem.nextSiblingElement(
"hash")) {
491 QString type = elem.attribute(
"type");
492 const QString hash = elem.text();
493 if (!type.isEmpty() && !hash.isEmpty()) {
499 for (QDomElement elem = e.firstChildElement(
"pieces"); !elem.isNull(); elem = elem.nextSiblingElement(
"pieces")) {
501 piecesItem.
load(elem);
502 pieces.append(piecesItem);
505 for (QDomElement elem = e.firstChildElement(
"signature"); !elem.isNull(); elem = elem.nextSiblingElement(
"signature")) {
506 QString type = elem.attribute(
"mediatype");
507 if (type ==
"application/pgp-signature") {
510 const QString siganture = elem.text();
511 if (!type.isEmpty() && !siganture.isEmpty()) {
512 signatures[type] = siganture;
519 QDomDocument doc = e.ownerDocument();
521 QHash<QString, QString>::const_iterator it;
522 QHash<QString, QString>::const_iterator itEnd = hashes.constEnd();
523 for (it = hashes.constBegin(); it != itEnd; ++it) {
524 QDomElement hash = doc.createElement(
"hash");
526 QDomText text = doc.createTextNode(it.value());
527 hash.appendChild(text);
531 foreach (
const Pieces &item, pieces) {
535 itEnd = signatures.constEnd();
536 for (it = signatures.constBegin(); it != itEnd; ++it) {
537 QString type = it.key();
539 type =
"application/pgp-signature";
541 QDomElement hash = doc.createElement(
"signature");
542 hash.setAttribute(
"mediatype", type);
543 QDomText text = doc.createTextNode(it.value());
544 hash.appendChild(text);
557 return isValidNameAttribute() && resources.isValid();
564 name = QUrl::fromPercentEncoding(e.attribute(
"name").toAscii());
565 size = e.firstChildElement(
"size").text().toULongLong();
567 verification.load(e);
575 QDomDocument doc = e.ownerDocument();
576 QDomElement file = doc.createElement(
"file");
577 file.setAttribute(
"name", name);
581 QDomElement elem = doc.createElement(
"size");
582 QDomText text = doc.createTextNode(QString::number(size));
583 elem.appendChild(text);
584 file.appendChild(elem);
588 resources.save(file);
589 verification.save(file);
598 verification.clear();
607 if (name.isEmpty()) {
608 kError(5001) <<
"Name attribute of Metalink::File is empty.";
612 if (name.endsWith(
'/')) {
613 kError(5001) <<
"Name attribute of Metalink::File does not contain a file name:" << name;
617 const QStringList components = name.split(
'/');
618 if (name.startsWith(
'/') || components.contains(
"..") || components.contains(
".")) {
619 kError(5001) <<
"Name attribute of Metalink::File contains directory traversal directives:" << name;
627 QList<QPair<QUrl, Nepomuk2::Variant> > KGetMetalink::File::properties()
const
629 return data.properties();
631 #endif //HAVE_NEPOMUK
635 if (files.isEmpty()) {
639 QStringList fileNames;
640 foreach (
const File &file, files) {
641 fileNames << file.
name;
648 while (!fileNames.isEmpty()) {
649 const QString fileName = fileNames.takeFirst();
650 if (fileNames.contains(fileName)) {
651 kError(5001) <<
"Metalink::File name" << fileName <<
"exists multiple times.";
661 for (QDomElement elem = e.firstChildElement(
"file"); !elem.isNull(); elem = elem.nextSiblingElement(
"file"))
676 foreach (
const File &file, files)
689 return files.isValid();
701 QDomDocument doc = e.ownerDocument();
702 const QDomElement metalink = doc.firstChildElement(
"metalink");
704 xmlns = metalink.attribute(
"xmlns");
705 generator = metalink.firstChildElement(
"generator").text();
706 updated.setData(metalink.firstChildElement(
"updated").text());
707 published.setData(metalink.firstChildElement(
"published").text());
708 updated.setData(metalink.firstChildElement(
"updated").text());
709 const QDomElement originElem = metalink.firstChildElement(
"origin");
710 origin = KUrl(metalink.firstChildElement(
"origin").text());
711 if (originElem.hasAttribute(
"dynamic")) {
713 dynamic = originElem.attribute(
"dynamic").toInt(&worked);
715 dynamic = (originElem.attribute(
"dynamic") ==
"true");
725 QDomProcessingInstruction header = doc.createProcessingInstruction(
"xml",
"version=\"1.0\" encoding=\"UTF-8\"");
726 doc.appendChild(header);
728 QDomElement metalink = doc.createElement(
"metalink");
729 metalink.setAttribute(
"xmlns",
"urn:ietf:params:xml:ns:metalink");
731 QDomElement elem = doc.createElement(
"generator");
732 QDomText text = doc.createTextNode(Metalink::KGET_DESCRIPTION);
733 elem.appendChild(text);
734 metalink.appendChild(elem);
736 if (!origin.isEmpty()) {
737 QDomElement elem = doc.createElement(
"origin");
738 QDomText text = doc.createTextNode(origin.url());
739 elem.appendChild(text);
741 elem.setAttribute(
"dynamic",
"true");
743 metalink.appendChild(elem);
745 if (published.isValid()) {
746 QDomElement elem = doc.createElement(
"published");
747 QDomText text = doc.createTextNode(published.toString());
748 elem.appendChild(text);
749 metalink.appendChild(elem);
751 if (updated.isValid()) {
752 QDomElement elem = doc.createElement(
"updated");
753 QDomText text = doc.createTextNode(updated.toString());
754 elem.appendChild(text);
755 metalink.appendChild(elem);
758 files.save(metalink);
760 doc.appendChild(metalink);
787 m_metalink = metalink;
792 QDomDocument doc = e.ownerDocument();
793 const QDomElement metalinkDom = doc.firstChildElement(
"metalink");
795 m_metalink.dynamic = (metalinkDom.attribute(
"type") ==
"dynamic");
796 m_metalink.origin = KUrl(metalinkDom.attribute(
"origin"));
797 m_metalink.generator = metalinkDom.attribute(
"generator");
798 m_metalink.published = parseDateConstruct(metalinkDom.attribute(
"pubdate"));
799 m_metalink.updated = parseDateConstruct(metalinkDom.attribute(
"refreshdate"));
801 parseFiles(metalinkDom);
804 void KGetMetalink::Metalink_v3::parseFiles(
const QDomElement &e)
808 data = parseCommonData(e);
810 const QDomElement filesElem = e.firstChildElement(
"files");
811 CommonData filesData = parseCommonData(filesElem);
813 inheritCommonData(data, &filesData);
815 for (QDomElement elem = filesElem.firstChildElement(
"file"); !elem.isNull(); elem = elem.nextSiblingElement(
"file")) {
817 file.
name = QUrl::fromPercentEncoding(elem.attribute(
"name").toAscii());
818 file.
size = elem.firstChildElement(
"size").text().toULongLong();
820 file.
data = parseCommonData(elem);
821 inheritCommonData(filesData, &file.
data);
826 QDomElement veriE = elem.firstChildElement(
"verification");
828 for (QDomElement elemVer = veriE.firstChildElement(
"hash"); !elemVer.isNull(); elemVer = elemVer.nextSiblingElement(
"hash")) {
829 QString type = elemVer.attribute(
"type");
830 QString hash = elemVer.text();
831 if (!type.isEmpty() && !hash.isEmpty()) {
837 for (QDomElement elemVer = veriE.firstChildElement(
"pieces"); !elemVer.isNull(); elemVer = elemVer.nextSiblingElement(
"pieces")) {
839 piecesItem.load(elemVer);
843 for (QDomElement elemVer = veriE.firstChildElement(
"signature"); !elemVer.isNull(); elemVer = elemVer.nextSiblingElement(
"signature")) {
844 const QString type = elemVer.attribute(
"type");
845 const QString signature = elemVer.text();
846 if (!type.isEmpty() && !signature.isEmpty()) {
851 m_metalink.files.files.append(file);
861 const QDomElement publisherElem = e.firstChildElement(
"publisher");
862 data.publisher.name = publisherElem.firstChildElement(
"name").text();
863 data.publisher.url = KUrl(publisherElem.firstChildElement(
"url").text());
875 if (inheritor->
identity.isEmpty()) {
878 if (inheritor->
version.isEmpty()) {
884 if (inheritor->
oses.isEmpty()) {
887 if (inheritor->
logo.isEmpty()) {
905 QDomElement res = e.firstChildElement(
"resources");
906 for (QDomElement elemRes = res.firstChildElement(
"url"); !elemRes.isNull(); elemRes = elemRes.nextSiblingElement(
"url")) {
907 const QString location = elemRes.attribute(
"location").toLower();
909 uint preference = elemRes.attribute(
"preference").toUInt();
911 if (preference > MAX_PREFERENCE) {
912 preference = MAX_PREFERENCE;
914 const int priority = MAX_PREFERENCE - preference + 1;
916 const KUrl link = KUrl(elemRes.text());
919 if (link.fileName().endsWith(QLatin1String(
".torrent"))) {
923 if (type.isEmpty()) {
926 url.priority = priority;
928 url.location = location;
931 resources.
urls.append(url);
937 metaurl.priority = priority;
941 if (metaurl.isValid()) {
942 resources.metaurls.append(metaurl);
952 DateConstruct dateConstruct;
955 return dateConstruct;
958 kDebug(5001) <<
"Parsing" << data;
962 QTime timeZoneOffset;
968 const QString weekdayExp =
"ddd, ";
969 const bool weekdayIncluded = (temp.indexOf(
',') == 3);
970 int startPosition = (weekdayIncluded ? weekdayExp.length() : 0);
971 const QString dayMonthExp =
"dd MMM ";
972 const QString yearExp =
"yy";
974 QString exp = dayMonthExp + yearExp + yearExp;
975 int length = exp.length();
977 QLocale locale = QLocale::c();
978 QDate date = locale.toDate(temp.mid(startPosition, length), exp);
979 if (!date.isValid()) {
980 exp = dayMonthExp + yearExp;
981 length = exp.length();
982 date = locale.toDate(temp.mid(startPosition, length), exp);
983 if (!date.isValid()) {
984 return dateConstruct;
989 dateTime.setDate(date);
990 temp = temp.mid(startPosition);
991 temp = temp.mid(length + 1);
993 const QString hourExp =
"hh";
994 const QString minuteExp =
"mm";
995 const QString secondExp =
"ss";
997 exp = hourExp +
':' + minuteExp +
':' + secondExp;
998 length = exp.length();
999 QTime time = QTime::fromString(temp.left(length), exp);
1000 if (!time.isValid()) {
1001 exp = hourExp +
':' + minuteExp;
1002 length = exp.length();
1003 time = QTime::fromString(temp.left(length), exp);
1004 if (!time.isValid()) {
1005 return dateConstruct;
1008 dateTime.setTime(time);
1011 temp = temp.mid(length + 1);
1012 bool negativeOffset =
false;
1014 if (temp.length() == 3) {
1015 KTimeZone timeZone = KSystemTimeZones::readZone(temp);
1016 if (timeZone.isValid()) {
1017 int offset = timeZone.currentOffset();
1018 negativeOffset = (offset < 0);
1019 timeZoneOffset = QTime(0, 0, 0);
1020 timeZoneOffset = timeZoneOffset.addSecs(qAbs(offset));
1022 }
else if (temp.length() == 5) {
1023 negativeOffset = (temp[0] ==
'-');
1024 timeZoneOffset = QTime::fromString(temp.mid(1,4),
"hhmm");
1027 dateConstruct.setData(dateTime, timeZoneOffset, negativeOffset);
1029 return dateConstruct;
1035 QDomProcessingInstruction header = doc.createProcessingInstruction(
"xml",
"version=\"1.0\" encoding=\"UTF-8\"");
1036 doc.appendChild(header);
1038 QDomElement metalink = doc.createElement(
"metalink");
1039 metalink.setAttribute(
"xmlns",
"http://www.metalinker.org/");
1040 metalink.setAttribute(
"version",
"3.0");
1041 metalink.setAttribute(
"type", (m_metalink.dynamic ?
"dynamic" :
"static"));
1042 metalink.setAttribute(
"generator", Metalink::KGET_DESCRIPTION);
1044 if (m_metalink.published.isValid()) {
1045 metalink.setAttribute(
"pubdate", dateConstructToString(m_metalink.published));
1047 if (m_metalink.updated.isValid()) {
1048 metalink.setAttribute(
"refreshdate", dateConstructToString(m_metalink.updated));
1050 if (!m_metalink.origin.isEmpty()) {
1051 metalink.setAttribute(
"origin", m_metalink.origin.url());
1054 saveFiles(metalink);
1056 doc.appendChild(metalink);
1061 void KGetMetalink::Metalink_v3::saveFiles(QDomElement &e)
const
1063 QDomDocument doc = e.ownerDocument();
1064 QDomElement filesElem = doc.createElement(
"files");
1066 foreach (
const File &file, m_metalink.files.files) {
1067 QDomElement elem = doc.createElement(
"file");
1068 elem.setAttribute(
"name", file.
name);
1070 QDomElement size = doc.createElement(
"size");
1071 QDomText text = doc.createTextNode(QString::number(file.
size));
1072 size.appendChild(text);
1073 elem.appendChild(size);
1075 saveCommonData(file.
data, elem);
1079 filesElem.appendChild(elem);
1082 e.appendChild(filesElem);
1085 void KGetMetalink::Metalink_v3::saveResources(
const Resources &resources, QDomElement &e)
const
1087 QDomDocument doc = e.ownerDocument();
1088 QDomElement res = doc.createElement(
"resources");
1090 foreach (
const Url &url, resources.urls) {
1091 QDomElement elem = doc.createElement(
"url");
1092 const uint priority = url.priority;
1094 int preference = MAX_PREFERENCE - priority + 1;
1095 if (preference <= 0) {
1098 elem.setAttribute(
"preference", preference);
1100 if (!url.location.isEmpty()) {
1101 elem.setAttribute(
"location", url.location);
1104 QDomText text = doc.createTextNode(url.url.url());
1105 elem.appendChild(text);
1107 res.appendChild(elem);
1110 foreach (
const Metaurl &metaurl, resources.metaurls) {
1111 if (metaurl.type ==
"torrent") {
1112 QDomElement elem = doc.createElement(
"url");
1113 elem.setAttribute(
"type",
"bittorrent");
1114 const uint priority = metaurl.priority;
1116 int preference = MAX_PREFERENCE - priority + 1;
1117 if (preference <= 0) {
1120 elem.setAttribute(
"preference", preference);
1123 QDomText text = doc.createTextNode(metaurl.url.url());
1124 elem.appendChild(text);
1126 res.appendChild(elem);
1135 QDomDocument doc = e.ownerDocument();
1136 QDomElement veri = doc.createElement(
"verification");
1138 QHash<QString, QString>::const_iterator it;
1139 QHash<QString, QString>::const_iterator itEnd = verification.
hashes.constEnd();
1140 for (it = verification.
hashes.constBegin(); it != itEnd; ++it) {
1141 QDomElement elem = doc.createElement(
"hash");
1142 elem.setAttribute(
"type", it.key());
1143 QDomText text = doc.createTextNode(it.value());
1144 elem.appendChild(text);
1146 veri.appendChild(elem);
1149 foreach (
const Pieces &pieces, verification.
pieces) {
1150 QDomElement elem = doc.createElement(
"pieces");
1151 elem.setAttribute(
"type", pieces.type);
1152 elem.setAttribute(
"length", QString::number(pieces.length));
1154 for (
int i = 0; i < pieces.hashes.count(); ++i) {
1155 QDomElement hash = doc.createElement(
"hash");
1156 hash.setAttribute(
"piece", i);
1157 QDomText text = doc.createTextNode(pieces.hashes.at(i));
1158 hash.appendChild(text);
1160 elem.appendChild(hash);
1162 veri.appendChild(elem);
1166 for (it = verification.
signatures.constBegin(); it != itEnd; ++it) {
1167 QDomElement elem = doc.createElement(
"signature");
1168 elem.setAttribute(
"type", it.key());
1169 QDomText text = doc.createTextNode(it.value());
1170 elem.appendChild(text);
1172 veri.appendChild(elem);
1175 e.appendChild(veri);
1180 QDomDocument doc = e.ownerDocument();
1182 CommonData commonData = data;
1184 if (!commonData.publisher.isEmpty()) {
1185 QDomElement elem = doc.createElement(
"publisher");
1186 QDomElement elemName = doc.createElement(
"name");
1187 QDomElement elemUrl = doc.createElement(
"url");
1189 QDomText text = doc.createTextNode(commonData.publisher.name);
1190 elemName.appendChild(text);
1191 elem.appendChild(elemName);
1193 text = doc.createTextNode(commonData.publisher.url.url());
1194 elemUrl.appendChild(text);
1195 elem.appendChild(elemUrl);
1197 e.appendChild(elem);
1202 if (commonData.oses.count() > 1) {
1203 commonData.oses.clear();
1216 QLocale locale = QLocale::c();
1219 dateString += locale.toString(date.
dateTime,
"ddd, dd MMM yyyy hh:mm:ss ");
1225 dateString +=
"+0000";
1234 QFile file(destination.pathOrUrl());
1235 if (!file.open(QIODevice::ReadOnly))
1241 if (!doc.setContent(&file))
1248 QDomElement root = doc.documentElement();
1249 if (root.attribute(
"xmlns") ==
"urn:ietf:params:xml:ns:metalink")
1251 metalink->
load(root);
1254 else if ((root.attribute(
"xmlns") ==
"http://www.metalinker.org/") || (root.attribute(
"version") ==
"3.0"))
1257 metalink_v3.
load(root);
1258 *metalink = metalink_v3.
metalink();
1273 if (!doc.setContent(data))
1279 QDomElement root = doc.documentElement();
1280 if (root.attribute(
"xmlns") ==
"urn:ietf:params:xml:ns:metalink")
1282 metalink->
load(root);
1285 else if ((root.attribute(
"xmlns") ==
"http://www.metalinker.org/") || (root.attribute(
"version") ==
"3.0"))
1288 metalink_v3.
load(root);
1289 *metalink = metalink_v3.
metalink();
1298 QFile file(destination.pathOrUrl());
1299 if (!file.open(QIODevice::WriteOnly)) {
1304 QString fileName = destination.fileName();
1305 if (fileName.endsWith(QLatin1String(
"meta4"))) {
1306 doc = metalink->
save();
1307 }
else if (fileName.endsWith(QLatin1String(
"metalink"))) {
1310 doc = metalink_v3.
save();
1316 QTextStream stream(&file);
1317 doc.save(stream, 2);
1324 void KGetMetalink::HandleMetalink::addProperty(QList<QPair<QUrl, Nepomuk2::Variant> > *data,
const QByteArray &uriBa,
const QString &value)
1326 if (!uriBa.isEmpty()) {
1327 addProperty(data, QUrl::fromEncoded(uriBa, QUrl::StrictMode), value);
1331 void KGetMetalink::HandleMetalink::addProperty(QList<QPair<QUrl, Nepomuk2::Variant> > *data,
const QUrl &uri,
const QString &value)
1333 if (data && !uri.isEmpty() && !value.isEmpty()) {
1334 (*data) << qMakePair(uri, Nepomuk2::Variant(value));
1337 #endif //HAVE_NEPOMUK
1347 return &m_EtagValue;
1350 void KGetMetalink::MetalinkHttpParser::checkMetalinkHttp()
1352 if (!m_Url.isValid()) {
1353 kDebug() <<
"Url not valid";
1357 KIO::TransferJob *job;
1358 job = KIO::get(m_Url, KIO::NoReload, KIO::HideProgressInfo);
1359 job->addMetaData(
"PropagateHttpHeader",
"true");
1360 job->setRedirectionHandlingEnabled(
false);
1361 connect(job, SIGNAL(result(
KJob*)),
this, SLOT(slotHeaderResult(
KJob*)));
1362 connect(job, SIGNAL(redirection(KIO::Job*,KUrl)),
this, SLOT(slotRedirection(KIO::Job*,KUrl)));
1363 connect(job,SIGNAL(mimetype(KIO::Job*,QString)),
this,SLOT(detectMime(KIO::Job*,QString)));
1364 kDebug() <<
" Verifying Metalink/HTTP Status" ;
1368 void KGetMetalink::MetalinkHttpParser::detectMime(KIO::Job *job,
const QString &type)
1370 kDebug() <<
"Mime Type: " << type ;
1375 void KGetMetalink::MetalinkHttpParser::slotHeaderResult(
KJob* kjob)
1377 KIO::Job* job = qobject_cast<KIO::Job*>(kjob);
1378 const QString httpHeaders = job ? job->queryMetaData(
"HTTP-Headers") : QString();
1379 parseHeaders(httpHeaders);
1380 setMetalinkHSatus();
1383 if (m_redirectionUrl.isValid()) {
1384 m_Url = m_redirectionUrl;
1385 m_redirectionUrl = KUrl();
1386 checkMetalinkHttp();
1389 if (m_loop.isRunning())
1393 void KGetMetalink::MetalinkHttpParser::slotRedirection(KIO::Job *job,
const KUrl & url)
1396 m_redirectionUrl = url;
1401 if (m_MetalinkHSatus) {
1402 kDebug() <<
"Metalink Http detected" ;
1405 kDebug() <<
"No Metalink HTTP response found" ;
1407 return m_MetalinkHSatus;
1410 void KGetMetalink::MetalinkHttpParser::parseHeaders(
const QString &httpHeader)
1412 QString trimedHeader = httpHeader.mid(httpHeader.indexOf(
'\n') + 1).trimmed();
1414 foreach(QString line, trimedHeader.split(
'\n')) {
1415 int colon = line.indexOf(
':');
1416 QString headerName = line.left(colon).trimmed();
1417 QString headerValue = line.mid(colon + 1).trimmed();
1418 m_headerInfo.insertMulti(headerName, headerValue);
1421 m_EtagValue = m_headerInfo.value(
"ETag");
1424 void KGetMetalink::MetalinkHttpParser::setMetalinkHSatus()
1426 bool linkStatus, digestStatus;
1427 linkStatus = digestStatus =
false;
1428 if (m_headerInfo.contains(
"link")) {
1429 QList<QString> linkValues = m_headerInfo.values(
"link");
1431 foreach(QString linkVal, linkValues) {
1432 if (linkVal.contains(
"rel=duplicate")) {
1439 if (m_headerInfo.contains(
"digest")) {
1440 QList<QString> digestValues = m_headerInfo.values(
"digest");
1442 foreach(QString digestVal, digestValues) {
1443 if (digestVal.contains(
"sha-256", Qt::CaseInsensitive)) {
1444 digestStatus =
true;
1450 if ((linkStatus) && (digestStatus)) {
1451 m_MetalinkHSatus =
true;
1463 return & m_headerInfo;
1474 return depth < other.
depth;
1479 url = line.mid(line.indexOf(
"<") + 1,line.indexOf(
">") -1).trimmed();
1480 const QList<QString> attribList = line.split(
";");
1482 foreach (
const QString str, attribList) {
1483 const QString attribId = str.mid(0,str.indexOf(
"=")).trimmed();
1484 const QString attribValue = str.mid(str.indexOf(
"=")+1).trimmed();
1486 if (attribId ==
"rel") {
1487 reltype = attribValue;
1489 else if (attribId ==
"depth") {
1490 depth = attribValue.toInt();
1492 else if (attribId ==
"geo") {
1495 else if (attribId ==
"pref") {
1498 else if (attribId ==
"pri") {
1499 priority = attribValue.toUInt();
1501 else if (attribId ==
"type") {
1504 else if (attribId ==
"name") {
1510 #include "metalinker.moc"