2 // This file is part of the aMule Project.
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
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
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.
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 "SearchFile.h" // Interface declarations.
28 #include <tags/FileTags.h>
30 #include "amule.h" // Needed for theApp
31 #include "CanceledFileList.h"
32 #include "MemFile.h" // Needed for CMemFile
33 #include "Preferences.h" // Needed for thePrefs
34 #include "GuiEvents.h"
36 #include "PartFile.h" // Needed for CPartFile::CanAddSource
37 #include "DownloadQueue.h" // Needed for CDownloadQueue
38 #include "KnownFileList.h" // Needed for CKnownFileList
40 CSearchFile::CSearchFile(const CMemFile
& data
, bool optUTF8
, wxUIntPtr searchID
, uint32_t serverIP
, uint16_t serverPort
, const wxString
& directory
, bool kademlia
)
42 m_showChildren(false),
45 m_completeSourceCount(0),
47 m_downloadStatus(NEW
),
48 m_directory(directory
),
49 m_clientServerIP(serverIP
),
50 m_clientServerPort(serverPort
),
53 m_abyFileHash
= data
.ReadHash();
55 m_clientID
= data
.ReadUInt32();
56 m_clientPort
= data
.ReadUInt16();
58 if (!m_clientID
|| !m_clientPort
|| !IsGoodIP(m_clientID
, thePrefs::FilterLanIPs())) {
63 uint32 tagcount
= data
.ReadUInt32();
64 for (unsigned int i
= 0; i
< tagcount
; ++i
) {
65 CTag
tag(data
, optUTF8
);
66 switch (tag
.GetNameID()) {
68 SetFileName(CPath(tag
.GetStr()));
71 SetFileSize(tag
.GetInt());
74 SetFileSize((((uint64
)tag
.GetInt()) << 32) + GetFileSize());
77 m_iUserRating
= (tag
.GetInt() & 0xF) / 3;
80 m_sourceCount
= tag
.GetInt();
82 case FT_COMPLETE_SOURCES
:
83 m_completeSourceCount
= tag
.GetInt();
86 case FT_KADLASTPUBLISHKEY
:
95 if (!GetFileName().IsOk()) {
96 throw CInvalidPacket(wxT("No filename in search result"));
101 CSearchFile::CSearchFile(const CSearchFile
& other
)
102 : CAbstractFile(other
),
103 CECID(), // create a new ID for now
104 m_parent(other
.m_parent
),
105 m_showChildren(other
.m_showChildren
),
106 m_searchID(other
.m_searchID
),
107 m_sourceCount(other
.m_sourceCount
),
108 m_completeSourceCount(other
.m_completeSourceCount
),
109 m_kademlia(other
.m_kademlia
),
110 m_downloadStatus(other
.m_downloadStatus
),
111 m_directory(other
.m_directory
),
112 m_clients(other
.m_clients
),
113 m_clientID(other
.m_clientID
),
114 m_clientPort(other
.m_clientPort
),
115 m_clientServerIP(other
.m_clientServerIP
),
116 m_clientServerPort(other
.m_clientServerPort
),
117 m_kadPublishInfo(other
.m_kadPublishInfo
)
119 for (size_t i
= 0; i
< other
.m_children
.size(); ++i
) {
120 m_children
.push_back(new CSearchFile(*other
.m_children
.at(i
)));
125 CSearchFile::~CSearchFile()
127 for (size_t i
= 0; i
< m_children
.size(); ++i
) {
128 delete m_children
.at(i
);
133 void CSearchFile::AddClient(const ClientStruct
& client
)
135 for (std::list
<ClientStruct
>::const_iterator it
= m_clients
.begin(); it
!= m_clients
.end(); ++it
) {
136 if (client
.m_ip
== it
->m_ip
&& client
.m_port
== it
->m_port
) return;
138 m_clients
.push_back(client
);
141 void CSearchFile::MergeResults(const CSearchFile
& other
)
145 m_sourceCount
= std::max(m_sourceCount
, other
.m_sourceCount
);
146 m_completeSourceCount
= std::max(m_completeSourceCount
, other
.m_completeSourceCount
);
148 m_sourceCount
+= other
.m_sourceCount
;
149 m_completeSourceCount
+= other
.m_completeSourceCount
;
153 if (m_kadPublishInfo
== 0) {
154 if (other
.m_kadPublishInfo
!= 0) {
155 m_kadPublishInfo
= other
.m_kadPublishInfo
;
158 if (other
.m_kadPublishInfo
!= 0) {
160 std::max(m_kadPublishInfo
& 0xFF000000, other
.m_kadPublishInfo
& 0xFF000000) |
161 std::max(m_kadPublishInfo
& 0x00FF0000, other
.m_kadPublishInfo
& 0x00FF0000) |
162 (((m_kadPublishInfo
& 0x0000FFFF) + (other
.m_kadPublishInfo
& 0x0000FFFF)) >> 1);
167 if (m_iUserRating
!= 0) {
168 if (other
.m_iUserRating
!= 0) {
169 m_iUserRating
= (m_iUserRating
+ other
.m_iUserRating
) / 2;
172 if (other
.m_iUserRating
!= 0) {
173 m_iUserRating
= other
.m_iUserRating
;
177 // copy possible available sources from new result
178 if (other
.GetClientID() && other
.GetClientPort()) {
179 // pre-filter sources which would be dropped by CPartFile::AddSources
180 if (CPartFile::CanAddSource(other
.GetClientID(), other
.GetClientPort(), other
.GetClientServerIP(), other
.GetClientServerPort())) {
181 CSearchFile::ClientStruct
client(other
.GetClientID(), other
.GetClientPort(), other
.GetClientServerIP(), other
.GetClientServerPort());
188 void CSearchFile::AddChild(CSearchFile
* file
)
190 wxCHECK_RET(file
, wxT("Not a valid child!"));
191 wxCHECK_RET(!file
->GetParent(), wxT("Search-result can only be child of one other result"));
192 wxCHECK_RET(!file
->HasChildren(), wxT("Result already has children, cannot become child."));
193 wxCHECK_RET(!GetParent(), wxT("A child cannot have children of its own"));
194 wxCHECK_RET(GetFileHash() == file
->GetFileHash(), wxT("Mismatching child/parent hashes"));
195 wxCHECK_RET(GetFileSize() == file
->GetFileSize(), wxT("Mismatching child/parent sizes"));
197 // If no children exists, then we add the current item.
198 if (GetChildren().empty()) {
199 // Merging duplicate names instead of adding a new one
200 if (file
->GetFileName() == GetFileName()) {
201 AddDebugLogLineN(logSearch
, CFormat(wxT("Merged results for '%s'")) % GetFileName());
206 // The first child will always be the first result we received.
207 AddDebugLogLineN(logSearch
, CFormat(wxT("Created initial child for result '%s'")) % GetFileName());
208 m_children
.push_back(new CSearchFile(*this));
209 m_children
.back()->m_parent
= this;
213 file
->m_parent
= this;
215 for (size_t i
= 0; i
< m_children
.size(); ++i
) {
216 CSearchFile
* other
= m_children
.at(i
);
217 // Merge duplicate filenames
218 if (other
->GetFileName() == file
->GetFileName()) {
219 other
->MergeResults(*file
);
227 m_children
.push_back(file
);
230 if (ShowChildren()) {
231 Notify_Search_Add_Result(file
);
236 void CSearchFile::UpdateParent()
238 wxCHECK_RET(!m_parent
, wxT("UpdateParent called on child item"));
240 uint32_t sourceCount
= 0; // ed2k: sum of all sources, kad: the max sources found
241 uint32_t completeSourceCount
= 0; // ed2k: sum of all sources, kad: the max sources found
242 uint32_t differentNames
= 0; // max known different names
243 uint32_t publishersKnown
= 0; // max publishers known
244 uint32_t trustValue
= 0; // average trust value
245 unsigned publishInfoTags
= 0;
246 unsigned ratingCount
= 0;
247 unsigned ratingTotal
= 0;
248 CSearchResultList::const_iterator best
= m_children
.begin();
249 for (CSearchResultList::const_iterator it
= m_children
.begin(); it
!= m_children
.end(); ++it
) {
250 const CSearchFile
* child
= *it
;
252 // Locate the most common name
253 if (child
->GetSourceCount() > (*best
)->GetSourceCount()) {
259 sourceCount
= std::max(sourceCount
, child
->m_sourceCount
);
260 completeSourceCount
= std::max(completeSourceCount
, child
->m_completeSourceCount
);
262 sourceCount
+= child
->m_sourceCount
;
263 completeSourceCount
+= child
->m_completeSourceCount
;
267 if (child
->GetKadPublishInfo() != 0) {
268 differentNames
= std::max(differentNames
, (child
->GetKadPublishInfo() & 0xFF000000) >> 24);
269 publishersKnown
= std::max(publishersKnown
, (child
->GetKadPublishInfo() & 0x00FF0000) >> 16);
270 trustValue
+= child
->GetKadPublishInfo() & 0x0000FFFF;
275 if (child
->HasRating()) {
277 ratingTotal
+= child
->UserRating();
281 if (child
->GetClientID() && child
->GetClientPort()) {
282 CSearchFile::ClientStruct
client(child
->GetClientID(), child
->GetClientPort(), child
->GetClientServerIP(), child
->GetClientServerPort());
285 for (std::list
<ClientStruct
>::const_iterator cit
= child
->m_clients
.begin(); cit
!= child
->m_clients
.end(); ++cit
) {
290 m_sourceCount
= sourceCount
;
291 m_completeSourceCount
= completeSourceCount
;
293 if (publishInfoTags
> 0) {
294 m_kadPublishInfo
= ((differentNames
& 0x000000FF) << 24) | ((publishersKnown
& 0x000000FF) << 16) | ((trustValue
/ publishInfoTags
) & 0x0000FFFF);
296 m_kadPublishInfo
= 0;
299 if (ratingCount
> 0) {
300 m_iUserRating
= ratingTotal
/ ratingCount
;
305 SetFileName((*best
)->GetFileName());
308 void CSearchFile::SetDownloadStatus()
310 bool isPart
= theApp
->downloadqueue
->GetFileByID(m_abyFileHash
) != NULL
;
311 bool isKnown
= theApp
->knownfiles
->FindKnownFileByID(m_abyFileHash
) != NULL
;
312 bool isCanceled
= theApp
->canceledfiles
->IsCanceledFile(m_abyFileHash
);
314 if (isCanceled
&& isPart
) {
315 m_downloadStatus
= QUEUEDCANCELED
;
316 } else if (isCanceled
) {
317 m_downloadStatus
= CANCELED
;
319 m_downloadStatus
= QUEUED
;
320 } else if (isKnown
) {
321 m_downloadStatus
= DOWNLOADED
;
323 m_downloadStatus
= NEW
;
325 // Update status of children too
326 for (CSearchResultList::iterator it
= m_children
.begin(); it
!= m_children
.end(); ++it
) {
327 Notify_Search_Update_Sources(*it
);
331 // File_checked_for_headers