|  | @@ -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
 |