commit 5107e4b7a050d7533f44801f5f5f5694203fd3b5 Author: Joris Guisson Date: Wed Jul 11 20:16:43 2012 +0200 Make sure all trackers are used of a magnet link BUG: 302997 BUG: 303269 diff --git a/src/magnet/magnetlink.cpp b/src/magnet/magnetlink.cpp index 525bfa5..43168dc 100644 --- a/src/magnet/magnetlink.cpp +++ b/src/magnet/magnetlink.cpp @@ -19,13 +19,14 @@ ***************************************************************************/ #include "magnetlink.h" +#include #include #include #include namespace bt { - + MagnetLink::MagnetLink() { } @@ -44,7 +45,7 @@ namespace bt { parse(mlink); } - + MagnetLink::~MagnetLink() { } @@ -64,83 +65,114 @@ namespace bt { return info_hash == mlink.infoHash(); } - + + static KUrl::List GetTrackers(const KUrl & url) + { + KUrl::List result; + const QString encoded_query = QString::fromLatin1(url.encodedQuery()); + const QString item = QLatin1String("tr="); + if(encoded_query.length() <= 1) + return result; + + const QStringList items = encoded_query.split(QString(QLatin1Char('&')), QString::SkipEmptyParts); + const int len = item.length(); + for(QStringList::ConstIterator it = items.begin(); it != items.end(); ++it) + { + if((*it).startsWith(item)) + { + if((*it).length() > len) + { + QString str = (*it).mid(len); + str.replace(QLatin1Char('+'), QLatin1Char(' ')); // + in queries means space. + result.push_back(QUrl::fromPercentEncoding(str.toLatin1())); + } + } + } + + return result; + } + void MagnetLink::parse(const QString& mlink) { KUrl url(mlink); - if (url.protocol() != "magnet") + if(url.protocol() != "magnet") { - Out(SYS_GEN|LOG_NOTICE) << "Invalid protocol of magnet link " - << mlink << endl; + Out(SYS_GEN | LOG_NOTICE) << "Invalid protocol of magnet link " + << mlink << endl; return; } - + torrent_url = url.queryItem("to"); //magnet://description-of-content.btih.HASH(-HASH)*.dht/path/file?x.pt=&x.to= // TODO automatically select these files and prefetches from here path = url.queryItem("pt"); - if ( path.isEmpty() && url.hasPath() && url.path() != "/" ) { + if(path.isEmpty() && url.hasPath() && url.path() != "/") + { // TODO find out why RemoveTrailingSlash does not work path = url.path(KUrl::RemoveTrailingSlash).remove(QRegExp("^/")); } QString xt = url.queryItem("xt"); - if ( xt.isEmpty() - || !xt.startsWith("urn:btih:") ) { + if(xt.isEmpty() + || !xt.startsWith("urn:btih:")) + { QRegExp btihHash("([^\\.]+).btih"); - if ( btihHash.indexIn(url.host()) != -1 ) { + if(btihHash.indexIn(url.host()) != -1) + { QString primaryHash = btihHash.cap(1).split("-")[0]; - xt = "urn:btih:"+primaryHash; - } else { - Out(SYS_GEN|LOG_NOTICE) << "No hash found in magnet link " - << mlink << endl; + xt = "urn:btih:" + primaryHash; + } + else + { + Out(SYS_GEN | LOG_NOTICE) << "No hash found in magnet link " + << mlink << endl; return; } } - + QString ih = xt.mid(9); - if (ih.length() != 40 && ih.length() != 32) + if(ih.length() != 40 && ih.length() != 32) { - Out(SYS_GEN|LOG_NOTICE) << "Hash has not valid length in magnet link " - << mlink << endl; + Out(SYS_GEN | LOG_NOTICE) << "Hash has not valid length in magnet link " + << mlink << endl; return; } - + try { - if (ih.length() == 32) + if(ih.length() == 32) ih = base32ToHexString(ih); Uint8 hash[20]; - memset(hash,0,20); - for (int i = 0;i < 20;i++) + memset(hash, 0, 20); + for(int i = 0; i < 20; i++) { - Uint8 low = charToHex(ih[2*i + 1]); - Uint8 high = charToHex(ih[2*i]); + Uint8 low = charToHex(ih[2 * i + 1]); + Uint8 high = charToHex(ih[2 * i]); hash[i] = (high << 4) | low; } - + info_hash = SHA1Hash(hash); - tracker_urls = url.queryItem("tr").split(","); + tracker_urls = GetTrackers(url); name = url.queryItem("dn"); magnet_string = mlink; } - catch (...) + catch(...) { - Out(SYS_GEN|LOG_NOTICE) << "Invalid magnet link " << mlink << endl; + Out(SYS_GEN | LOG_NOTICE) << "Invalid magnet link " << mlink << endl; } } - + Uint8 MagnetLink::charToHex(const QChar& ch) { - if (ch.isDigit()) + if(ch.isDigit()) return ch.digitValue(); - - if (!ch.isLetter()) + + if(!ch.isLetter()) throw bt::Error("Invalid char"); - - if (ch.isLower()) + + if(ch.isLower()) return 10 + ch.toAscii() - 'a'; else return 10 + ch.toAscii() - 'A'; @@ -155,28 +187,28 @@ namespace bt QString str = s.toUpper(); // 32 base32 chars -> 40 hex chars // 4 base32 chars -> 5 hex chars - for (int i = 0; i < 8; i++) + for(int i = 0; i < 8; i++) { part = 0; - for (int j = 0; j < 4; j++) + for(int j = 0; j < 4; j++) { - ch = str[i*4 + j]; - if (ch.isDigit() && (ch.digitValue() < 2 || ch.digitValue() > 7)) + ch = str[i * 4 + j]; + if(ch.isDigit() && (ch.digitValue() < 2 || ch.digitValue() > 7)) throw bt::Error("Invalid char"); - if (ch.isDigit()) - tmp = ch.digitValue() + 24; + if(ch.isDigit()) + tmp = ch.digitValue() + 24; else tmp = ch.toAscii() - 'A'; - part = part + (tmp << 5*(3-j)); + part = part + (tmp << 5 * (3 - j)); } // part is a Uint32 with 20 bits (5 hex) - for (int j = 0; j < 5; j++) + for(int j = 0; j < 5; j++) { - tmp = (part >> 4*(4-j)) & 0xf; - if (tmp >= 10) - ret.append(QChar((tmp-10) + 'a')); + tmp = (part >> 4 * (4 - j)) & 0xf; + if(tmp >= 10) + ret.append(QChar((tmp - 10) + 'a')); else ret.append(QChar(tmp + '0')); }