|
@@ -847,6 +847,64 @@ void generateRandomKey(unsigned char* key)
|
|
|
MessageDigestHelper::digest(key, 20, MessageDigestContext::SHA1, bytes, sizeof(bytes));
|
|
|
}
|
|
|
|
|
|
+void parseMagnetLink(const std::string& magnetLink,
|
|
|
+ const SharedHandle<DownloadContext>& dctx)
|
|
|
+{
|
|
|
+ // magnet:?xt=urn:btih:<info-hash>&dn=<name>&tr=<tracker-url>
|
|
|
+ // <info-hash> comes in 2 flavors: 40bytes hexadecimal ascii info hash,
|
|
|
+ // or 32bytes Base32 encoded info hash.
|
|
|
+ if(!util::startsWith(magnetLink, "magnet:?")) {
|
|
|
+ throw DL_ABORT_EX("Invalid magnet link.");
|
|
|
+ }
|
|
|
+ std::deque<std::string> queries;
|
|
|
+ util::split(std::string(magnetLink.begin()+8, magnetLink.end()),
|
|
|
+ std::back_inserter(queries), "&");
|
|
|
+ std::string infoHash;
|
|
|
+ std::string name;
|
|
|
+ BDE announceList = BDE::list();
|
|
|
+ announceList << BDE::list();
|
|
|
+ for(std::deque<std::string>::const_iterator i = queries.begin();
|
|
|
+ i != queries.end(); ++i) {
|
|
|
+ std::pair<std::string, std::string> kv;
|
|
|
+ util::split(kv, *i, '=');
|
|
|
+ if(kv.first == "xt") {
|
|
|
+ if(!util::startsWith(kv.second, "urn:btih:")) {
|
|
|
+ throw DL_ABORT_EX("Bad BitTorrent Magnet Link.");
|
|
|
+ }
|
|
|
+ if(infoHash.empty()) {
|
|
|
+ infoHash = kv.second.substr(9);
|
|
|
+ } else {
|
|
|
+ throw DL_ABORT_EX("More than 1 info hash in magnet link.");
|
|
|
+ }
|
|
|
+ } else if(kv.first == "dn") {
|
|
|
+ name = kv.second;
|
|
|
+ } else if(kv.first == "tr") {
|
|
|
+ announceList[0] << kv.second;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(infoHash.size() == 32) {
|
|
|
+ // Not yet implemented
|
|
|
+ abort();
|
|
|
+ } else if(infoHash.size() == 40) {
|
|
|
+ std::string rawhash = util::fromHex(infoHash);
|
|
|
+ if(rawhash.empty()) {
|
|
|
+ throw DL_ABORT_EX("Invalid info hash");
|
|
|
+ }
|
|
|
+ infoHash = rawhash;
|
|
|
+ } else {
|
|
|
+ throw DL_ABORT_EX("Invalid magnet link.");
|
|
|
+ }
|
|
|
+ if(name.empty()) {
|
|
|
+ name = util::toHex(infoHash);
|
|
|
+ }
|
|
|
+ BDE attrs = BDE::dict();
|
|
|
+ attrs[INFO_HASH] = infoHash;
|
|
|
+ attrs[NAME] = name;
|
|
|
+ attrs[ANNOUNCE_LIST] = announceList;
|
|
|
+
|
|
|
+ dctx->setAttribute(BITTORRENT, attrs);
|
|
|
+}
|
|
|
+
|
|
|
} // namespace bittorrent
|
|
|
|
|
|
} // namespace aria2
|