Upstream tarball 20080414
[amule.git] / src / ED2KLink.cpp
blobc49c2903d595d3a7a9bb9d65a43753c9ab02ecf9
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include <wx/wx.h>
28 #include "ED2KLink.h" // Interface declarations.
30 #include <wx/string.h>
31 #include <wx/regex.h> // Needed for wxRegEx
32 #include <wx/tokenzr.h> // Needed for wxStringTokenizer
34 #include <protocol/ed2k/Constants.h>
36 #include "MemFile.h" // Needed for CMemFile
37 #include "NetworkFunctions.h" // Needed for Uint32toStringIP
41 CED2KLink::CED2KLink( LinkType type )
42 : m_type( type )
47 CED2KLink::~CED2KLink()
52 CED2KLink::LinkType CED2KLink::GetKind() const
54 return m_type;
58 CED2KLink* CED2KLink::CreateLinkFromUrl(const wxString& link)
60 wxRegEx re_type(wxT("ed2k://\\|(file|server|serverlist)\\|.*/"), wxRE_ICASE | wxRE_DEFAULT);
61 wxCHECK(re_type.IsValid(), NULL);
63 if (!re_type.Matches(link)) {
64 throw wxString(wxT("Not a valid ed2k-URI"));
67 wxString type = re_type.GetMatch(link, 1).MakeLower();
68 wxCHECK(type.Length(), NULL);
70 if (type == wxT("file")) {
71 return new CED2KFileLink(link);
72 } else if (type == wxT("server")) {
73 return new CED2KServerLink(link);
74 } else if (type == wxT("serverlist")) {
75 return new CED2KServerListLink(link);
76 } else {
77 wxCHECK(false, NULL);
82 /////////////////////////////////////////////
83 // CED2KServerListLink implementation
84 /////////////////////////////////////////////
85 CED2KServerListLink::CED2KServerListLink(const wxString& link)
86 : CED2KLink( kServerList )
88 wxRegEx re(wxT("ed2k://\\|serverlist\\|(.*)\\|/"), wxRE_ICASE | wxRE_DEFAULT);
89 if (!re.Matches(link)) {
90 throw wxString(wxT("Not a valid server-list link."));
93 m_address = UnescapeHTML(re.GetMatch(link, 1));
97 wxString CED2KServerListLink::GetLink() const
99 return wxT("ed2k://|serverlist|") + m_address + wxT("|/");
103 const wxString& CED2KServerListLink::GetAddress() const
105 return m_address;
109 /////////////////////////////////////////////
110 // CED2KServerLink implementation
111 /////////////////////////////////////////////
112 CED2KServerLink::CED2KServerLink(const wxString& link)
113 : CED2KLink( kServer )
115 wxRegEx re(wxT("ed2k://\\|server\\|([^\\|]+)\\|([0-9]+)\\|/"), wxRE_ICASE | wxRE_DEFAULT);
116 if (!re.Matches(link)) {
117 throw wxString(wxT("Not a valid server link."));
120 wxString ip = UnescapeHTML(re.GetMatch(link, 1));
121 wxString port = re.GetMatch(link, 2);
123 unsigned long ul = StrToULong(port);
124 if (ul > 0xFFFF || ul == 0) {
125 throw wxString( wxT("Bad port number") );
128 m_port = static_cast<uint16>(ul);
129 m_ip = StringIPtoUint32(ip);
133 wxString CED2KServerLink::GetLink() const
135 return wxString(wxT("ed2k://|server|")) << Uint32toStringIP(m_ip) << wxT("|") << m_port << wxT("|/");
139 uint32 CED2KServerLink::GetIP() const
141 return m_ip;
145 uint16 CED2KServerLink::GetPort() const
147 return m_port;
151 /////////////////////////////////////////////
152 // CED2KFileLink implementation
153 /////////////////////////////////////////////
154 CED2KFileLink::CED2KFileLink(const wxString& link)
155 : CED2KLink( kFile ),
156 m_hashset(NULL),
157 m_size(0),
158 m_bAICHHashValid(false)
160 // Start tokenizing after the "ed2k:://|file|" part of the link
161 wxStringTokenizer tokens(link.Mid(13), wxT("|/"), wxTOKEN_RET_EMPTY_ALL);
163 // Must at least be ed2k://|file|NAME|SIZE|HASH|/
164 if (tokens.CountTokens() < 5) {
165 throw wxString(wxT("Not a valid file link"));
168 m_name = UnescapeHTML(tokens.GetNextToken().Strip(wxString::both));
170 // Note that StrToULong returns ULONG_MAX if the value is
171 // too large to be contained in a unsigned long, which means
172 // that this check is valid, as odd as it seems
173 wxString size = tokens.GetNextToken().Strip(wxString::both);
174 m_size = StrToULongLong(size);
175 if ((m_size == 0) || (m_size > MAX_FILE_SIZE)) {
176 throw wxString::Format(wxT("Invalid file size %i"), m_size);
179 if (!m_hash.Decode(tokens.GetNextToken().Strip(wxString::both))) {
180 throw wxString(wxT("Invalid hash"));
183 // Check extra fields (sources, parthashes, masterhashes)
184 while (tokens.HasMoreTokens()) {
185 wxString field = tokens.GetNextToken().MakeLower().Strip(wxString::both);
187 if (field.StartsWith(wxT("sources,"))) {
188 wxStringTokenizer srcTokens(field, wxT(","));
189 // Skipping the first token ("sources").
190 wxString token = srcTokens.GetNextToken();
191 while (srcTokens.HasMoreTokens()) {
192 token = srcTokens.GetNextToken().Strip(wxString::both);
194 wxStringTokenizer sourceTokens(token, wxT(":"));
195 wxString addr = sourceTokens.GetNextToken();
196 if (addr.IsEmpty()) {
197 throw wxString( wxT("Empty address" ) );
200 wxString strport = sourceTokens.GetNextToken();
201 if (strport.IsEmpty()) {
202 throw wxString( wxT("Empty port" ) );
205 unsigned port = StrToULong(strport);
207 // Sanity checking
208 if ((port == 0) || (port > 0xFFFF)) {
209 throw wxString( wxT("Invalid Port" ) );
212 wxString sourcehash;
213 uint8 cryptoptions =0;
214 wxString strcryptoptions = sourceTokens.GetNextToken();
215 if (!strcryptoptions.IsEmpty()) {
216 cryptoptions = (uint8) StrToULong(strcryptoptions);
217 if ((cryptoptions & 0x80) > 0) {
218 // Source ready for encryption, hash included.
219 sourcehash = sourceTokens.GetNextToken();
220 if (sourcehash.IsEmpty()) {
221 throw wxString( wxT("Empty sourcehash conflicts with cryptoptions flag 0x80" ) );
226 SED2KLinkSource entry = { addr, port, sourcehash, cryptoptions };
228 m_sources.push_back(entry);
230 } else if (field.StartsWith(wxT("p="))) {
231 wxStringTokenizer hashTokens(field.AfterFirst(wxT('=')), wxT(":"), wxTOKEN_RET_EMPTY_ALL);
233 m_hashset = new CMemFile();
234 m_hashset->WriteHash(m_hash);
235 m_hashset->WriteUInt16(0);
237 while (hashTokens.HasMoreTokens()) {
238 CMD4Hash hash;
239 if (!hash.Decode(hashTokens.GetNextToken().Strip(wxString::both))) {
240 throw wxString(wxT("Invalid hash in part-hashes list"));
243 m_hashset->WriteHash(hash);
246 unsigned count = m_hashset->GetLength() / 16u - 1u;
248 if (count) {
249 m_hashset->Seek( 16, wxFromStart);
250 m_hashset->WriteUInt16( count );
251 m_hashset->Seek( 0, wxFromStart);
252 } else {
253 delete m_hashset;
254 m_hashset = NULL;
256 } else if (field.StartsWith(wxT("h="))) {
257 wxString hash = field.AfterFirst(wxT('=')).MakeUpper();
259 size_t decodedSize = DecodeBase32(hash, CAICHHash::GetHashSize(), m_AICHHash.GetRawHash());
260 if ((decodedSize != CAICHHash::GetHashSize()) || m_AICHHash.GetString() != hash) {
261 throw wxString(wxT("Invalid master-hash"));
264 m_bAICHHashValid = true;
270 CED2KFileLink::~CED2KFileLink()
272 delete m_hashset;
273 m_hashset = NULL;
277 wxString CED2KFileLink::GetLink() const
279 return wxT("ed2k://|file|") + m_name + wxString::Format(wxT("|%u|"), m_size) + m_hash.Encode() + wxT("|/");
283 wxString CED2KFileLink::GetName() const
285 return m_name;
289 uint64 CED2KFileLink::GetSize() const
291 return m_size;
295 const CMD4Hash& CED2KFileLink::GetHashKey() const
297 return m_hash;
301 bool CED2KFileLink::HasValidAICHHash() const
303 return m_bAICHHashValid;
307 const CAICHHash& CED2KFileLink::GetAICHHash() const
309 return m_AICHHash;
311 // File_checked_for_headers