Upstream tarball 20080522
[amule.git] / src / SearchFile.cpp
blob660b7b371f73013ea42392be50ac97130edd8c50
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 "SearchFile.h" // Interface declarations.
28 #include <tags/FileTags.h>
30 #include "MemFile.h" // Needed for CMemFile
31 #include "Preferences.h" // Needed for thePrefs
32 #include "GuiEvents.h"
33 #include "Logger.h"
35 CSearchFile::CSearchFile(const CMemFile& data, bool optUTF8, wxUIntPtr searchID, uint32 WXUNUSED(serverIP), uint16 WXUNUSED(serverPort), const wxString& directory, bool kademlia)
36 : m_parent(NULL),
37 m_showChildren(false),
38 m_searchID(searchID),
39 m_sourceCount(0),
40 m_completeSourceCount(0),
41 m_kademlia(kademlia),
42 m_directory(directory),
43 m_kadPublishInfo(0)
45 m_abyFileHash = data.ReadHash();
46 m_clientID = data.ReadUInt32();
47 m_clientPort = data.ReadUInt16();
49 if ((!m_clientID) || (!m_clientPort)) {
50 m_clientID = m_clientPort = 0;
51 } else if (!IsGoodIP(m_clientID, thePrefs::FilterLanIPs())) {
52 m_clientID = m_clientPort = 0;
56 uint32 tagcount = data.ReadUInt32();
57 for (unsigned int i = 0; i < tagcount; ++i) {
58 CTag tag(data, optUTF8);
59 switch (tag.GetNameID()) {
60 case FT_FILENAME:
61 SetFileName(CPath(tag.GetStr()));
62 break;
63 case FT_FILESIZE:
64 SetFileSize(tag.GetInt());
65 break;
66 case FT_FILESIZE_HI:
67 SetFileSize((((uint64)tag.GetInt()) << 32) + GetFileSize());
68 break;
69 case FT_FILERATING:
70 m_iUserRating = (tag.GetInt() & 0xF) / 3;
71 break;
72 case FT_SOURCES:
73 m_sourceCount = tag.GetInt();
74 break;
75 case FT_COMPLETE_SOURCES:
76 m_completeSourceCount = tag.GetInt();
77 break;
78 default:
79 AddTagUnique(tag);
83 if (!GetFileName().IsOk()) {
84 throw CInvalidPacket(wxT("No filename in search result"));
89 CSearchFile::CSearchFile(const CSearchFile& other)
90 : CAbstractFile(other),
91 m_parent(other.m_parent),
92 m_showChildren(other.m_showChildren),
93 m_searchID(other.m_searchID),
94 m_sourceCount(other.m_sourceCount),
95 m_completeSourceCount(other.m_completeSourceCount),
96 m_kademlia(other.m_kademlia),
97 m_clientID(other.m_clientID),
98 m_clientPort(other.m_clientPort),
99 m_directory(other.m_directory),
100 m_kadPublishInfo(other.m_kadPublishInfo)
102 for (size_t i = 0; i < other.m_children.size(); ++i) {
103 m_children.push_back(new CSearchFile(*other.m_children.at(i)));
108 CSearchFile::~CSearchFile()
110 for (size_t i = 0; i < m_children.size(); ++i) {
111 delete m_children.at(i);
116 void CSearchFile::MergeResults(const CSearchFile& other)
118 // Sources
119 if (m_kademlia) {
120 m_sourceCount = std::max(m_sourceCount, other.m_sourceCount);
121 m_completeSourceCount = std::max(m_completeSourceCount, other.m_completeSourceCount);
122 } else {
123 m_sourceCount += other.m_sourceCount;
124 m_completeSourceCount += other.m_completeSourceCount;
127 // Publish info
128 if (m_kadPublishInfo == 0) {
129 if (other.m_kadPublishInfo != 0) {
130 m_kadPublishInfo = other.m_kadPublishInfo;
132 } else {
133 if (other.m_kadPublishInfo != 0) {
134 m_kadPublishInfo =
135 std::max(m_kadPublishInfo & 0xFF000000, other.m_kadPublishInfo & 0xFF000000) |
136 std::max(m_kadPublishInfo & 0x00FF0000, other.m_kadPublishInfo & 0x00FF0000) |
137 (((m_kadPublishInfo & 0x0000FFFF) + (other.m_kadPublishInfo & 0x0000FFFF)) >> 1);
141 // Rating
142 if (m_iUserRating != 0) {
143 if (other.m_iUserRating != 0) {
144 m_iUserRating = (m_iUserRating + other.m_iUserRating) / 2;
146 } else {
147 if (other.m_iUserRating != 0) {
148 m_iUserRating = other.m_iUserRating;
154 void CSearchFile::AddChild(CSearchFile* file)
156 wxCHECK_RET(file, wxT("Not a valid child!"));
157 wxCHECK_RET(!file->GetParent(), wxT("Search-result can only be child of one other result"));
158 wxCHECK_RET(!file->HasChildren(), wxT("Result already has children, cannot become child."));
159 wxCHECK_RET(!GetParent(), wxT("A child cannot have children of its own"));
160 wxCHECK_RET(GetFileHash() == file->GetFileHash(), wxT("Mismatching child/parent hashes"));
161 wxCHECK_RET(GetFileSize() == file->GetFileSize(), wxT("Mismatching child/parent sizes"));
163 // If no children exists, then we add the current item.
164 if (GetChildren().empty()) {
165 // Merging duplicate names instead of adding a new one
166 if (file->GetFileName() == GetFileName()) {
167 AddDebugLogLineM( false, logSearch, CFormat(wxT("Merged results for '%s'")) % GetFileName());
168 MergeResults(*file);
169 delete file;
170 return;
171 } else {
172 // The first child will always be the first result we received.
173 AddDebugLogLineM(false, logSearch, CFormat(wxT("Created initial child for result '%s'")) % GetFileName());
174 m_children.push_back(new CSearchFile(*this));
175 m_children.back()->m_parent = this;
179 file->m_parent = this;
181 for (size_t i = 0; i < m_children.size(); ++i) {
182 CSearchFile* other = m_children.at(i);
183 // Merge duplicate filenames
184 if (other->GetFileName() == file->GetFileName()) {
185 other->MergeResults(*file);
186 UpdateParent();
187 delete file;
188 return;
192 // New unique child.
193 m_children.push_back(file);
194 UpdateParent();
196 if (ShowChildren()) {
197 Notify_Search_Add_Result(file);
202 void CSearchFile::UpdateParent()
204 wxCHECK_RET(!m_parent, wxT("UpdateParent called on child item"));
206 uint32_t sourceCount = 0; // ed2k: sum of all sources, kad: the max sources found
207 uint32_t completeSourceCount = 0; // ed2k: sum of all sources, kad: the max sources found
208 uint32_t differentNames = 0; // max known different names
209 uint32_t publishersKnown = 0; // max publishers known
210 uint32_t trustValue = 0; // average trust value
211 unsigned publishInfoTags = 0;
212 unsigned ratingCount = 0;
213 unsigned ratingTotal = 0;
214 CSearchResultList::const_iterator best = m_children.begin();
215 for (CSearchResultList::const_iterator it = m_children.begin(); it != m_children.end(); ++it) {
216 const CSearchFile* child = *it;
218 // Locate the most common name
219 if (child->GetSourceCount() > (*best)->GetSourceCount()) {
220 best = it;
223 // Sources
224 if (m_kademlia) {
225 sourceCount = std::max(sourceCount, child->m_sourceCount);
226 completeSourceCount = std::max(completeSourceCount, child->m_completeSourceCount);
227 } else {
228 sourceCount += child->m_sourceCount;
229 completeSourceCount += child->m_completeSourceCount;
232 // Publish info
233 if (child->GetKadPublishInfo() != 0) {
234 differentNames = std::max(differentNames, (child->GetKadPublishInfo() & 0xFF000000) >> 24);
235 publishersKnown = std::max(publishersKnown, (child->GetKadPublishInfo() & 0x00FF0000) >> 16);
236 trustValue += child->GetKadPublishInfo() & 0x0000FFFF;
237 publishInfoTags++;
240 // Rating
241 if (child->HasRating()) {
242 ratingCount++;
243 ratingTotal += child->UserRating();
247 m_sourceCount = sourceCount;
248 m_completeSourceCount = completeSourceCount;
250 if (publishInfoTags > 0) {
251 m_kadPublishInfo = ((differentNames & 0x000000FF) << 24) | ((publishersKnown & 0x000000FF) << 16) | ((trustValue / publishInfoTags) & 0x0000FFFF);
252 } else {
253 m_kadPublishInfo = 0;
256 if (ratingCount > 0) {
257 m_iUserRating = ratingTotal / ratingCount;
258 } else {
259 m_iUserRating = 0;
262 SetFileName((*best)->GetFileName());
264 // File_checked_for_headers