Fix language getting reset to system default on saving preferences
[amule.git] / src / SearchFile.cpp
bloba84a7c9a880c5a2d578b752eef6edc9e720f1e64
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-2008 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 "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"
35 #include "Logger.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)
41 : m_parent(NULL),
42 m_showChildren(false),
43 m_searchID(searchID),
44 m_sourceCount(0),
45 m_completeSourceCount(0),
46 m_kademlia(kademlia),
47 m_downloadStatus(NEW),
48 m_directory(directory),
49 m_clientServerIP(serverIP),
50 m_clientServerPort(serverPort),
51 m_kadPublishInfo(0)
53 m_abyFileHash = data.ReadHash();
54 SetDownloadStatus();
55 m_clientID = data.ReadUInt32();
56 m_clientPort = data.ReadUInt16();
58 if (!m_clientID || !m_clientPort || !IsGoodIP(m_clientID, thePrefs::FilterLanIPs())) {
59 m_clientID = 0;
60 m_clientPort = 0;
63 uint32 tagcount = data.ReadUInt32();
64 for (unsigned int i = 0; i < tagcount; ++i) {
65 CTag tag(data, optUTF8);
66 switch (tag.GetNameID()) {
67 case FT_FILENAME:
68 SetFileName(CPath(tag.GetStr()));
69 break;
70 case FT_FILESIZE:
71 SetFileSize(tag.GetInt());
72 break;
73 case FT_FILESIZE_HI:
74 SetFileSize((((uint64)tag.GetInt()) << 32) + GetFileSize());
75 break;
76 case FT_FILERATING:
77 m_iUserRating = (tag.GetInt() & 0xF) / 3;
78 break;
79 case FT_SOURCES:
80 m_sourceCount = tag.GetInt();
81 break;
82 case FT_COMPLETE_SOURCES:
83 m_completeSourceCount = tag.GetInt();
84 break;
85 default:
86 AddTagUnique(tag);
90 if (!GetFileName().IsOk()) {
91 throw CInvalidPacket(wxT("No filename in search result"));
96 CSearchFile::CSearchFile(const CSearchFile& other)
97 : CAbstractFile(other),
98 CECID(), // create a new ID for now
99 m_parent(other.m_parent),
100 m_showChildren(other.m_showChildren),
101 m_searchID(other.m_searchID),
102 m_sourceCount(other.m_sourceCount),
103 m_completeSourceCount(other.m_completeSourceCount),
104 m_kademlia(other.m_kademlia),
105 m_downloadStatus(other.m_downloadStatus),
106 m_directory(other.m_directory),
107 m_clients(other.m_clients),
108 m_clientID(other.m_clientID),
109 m_clientPort(other.m_clientPort),
110 m_clientServerIP(other.m_clientServerIP),
111 m_clientServerPort(other.m_clientServerPort),
112 m_kadPublishInfo(other.m_kadPublishInfo)
114 for (size_t i = 0; i < other.m_children.size(); ++i) {
115 m_children.push_back(new CSearchFile(*other.m_children.at(i)));
120 CSearchFile::~CSearchFile()
122 for (size_t i = 0; i < m_children.size(); ++i) {
123 delete m_children.at(i);
128 void CSearchFile::AddClient(const ClientStruct& client)
130 for (std::list<ClientStruct>::const_iterator it = m_clients.begin(); it != m_clients.end(); ++it) {
131 if (client.m_ip == it->m_ip && client.m_port == it->m_port) return;
133 m_clients.push_back(client);
136 void CSearchFile::MergeResults(const CSearchFile& other)
138 // Sources
139 if (m_kademlia) {
140 m_sourceCount = std::max(m_sourceCount, other.m_sourceCount);
141 m_completeSourceCount = std::max(m_completeSourceCount, other.m_completeSourceCount);
142 } else {
143 m_sourceCount += other.m_sourceCount;
144 m_completeSourceCount += other.m_completeSourceCount;
147 // Publish info
148 if (m_kadPublishInfo == 0) {
149 if (other.m_kadPublishInfo != 0) {
150 m_kadPublishInfo = other.m_kadPublishInfo;
152 } else {
153 if (other.m_kadPublishInfo != 0) {
154 m_kadPublishInfo =
155 std::max(m_kadPublishInfo & 0xFF000000, other.m_kadPublishInfo & 0xFF000000) |
156 std::max(m_kadPublishInfo & 0x00FF0000, other.m_kadPublishInfo & 0x00FF0000) |
157 (((m_kadPublishInfo & 0x0000FFFF) + (other.m_kadPublishInfo & 0x0000FFFF)) >> 1);
161 // Rating
162 if (m_iUserRating != 0) {
163 if (other.m_iUserRating != 0) {
164 m_iUserRating = (m_iUserRating + other.m_iUserRating) / 2;
166 } else {
167 if (other.m_iUserRating != 0) {
168 m_iUserRating = other.m_iUserRating;
172 // copy possible available sources from new result
173 if (other.GetClientID() && other.GetClientPort()) {
174 // pre-filter sources which would be dropped by CPartFile::AddSources
175 if (CPartFile::CanAddSource(other.GetClientID(), other.GetClientPort(), other.GetClientServerIP(), other.GetClientServerPort())) {
176 CSearchFile::ClientStruct client(other.GetClientID(), other.GetClientPort(), other.GetClientServerIP(), other.GetClientServerPort());
177 AddClient(client);
183 void CSearchFile::AddChild(CSearchFile* file)
185 wxCHECK_RET(file, wxT("Not a valid child!"));
186 wxCHECK_RET(!file->GetParent(), wxT("Search-result can only be child of one other result"));
187 wxCHECK_RET(!file->HasChildren(), wxT("Result already has children, cannot become child."));
188 wxCHECK_RET(!GetParent(), wxT("A child cannot have children of its own"));
189 wxCHECK_RET(GetFileHash() == file->GetFileHash(), wxT("Mismatching child/parent hashes"));
190 wxCHECK_RET(GetFileSize() == file->GetFileSize(), wxT("Mismatching child/parent sizes"));
192 // If no children exists, then we add the current item.
193 if (GetChildren().empty()) {
194 // Merging duplicate names instead of adding a new one
195 if (file->GetFileName() == GetFileName()) {
196 AddDebugLogLineN(logSearch, CFormat(wxT("Merged results for '%s'")) % GetFileName());
197 MergeResults(*file);
198 delete file;
199 return;
200 } else {
201 // The first child will always be the first result we received.
202 AddDebugLogLineN(logSearch, CFormat(wxT("Created initial child for result '%s'")) % GetFileName());
203 m_children.push_back(new CSearchFile(*this));
204 m_children.back()->m_parent = this;
208 file->m_parent = this;
210 for (size_t i = 0; i < m_children.size(); ++i) {
211 CSearchFile* other = m_children.at(i);
212 // Merge duplicate filenames
213 if (other->GetFileName() == file->GetFileName()) {
214 other->MergeResults(*file);
215 UpdateParent();
216 delete file;
217 return;
221 // New unique child.
222 m_children.push_back(file);
223 UpdateParent();
225 if (ShowChildren()) {
226 Notify_Search_Add_Result(file);
231 void CSearchFile::UpdateParent()
233 wxCHECK_RET(!m_parent, wxT("UpdateParent called on child item"));
235 uint32_t sourceCount = 0; // ed2k: sum of all sources, kad: the max sources found
236 uint32_t completeSourceCount = 0; // ed2k: sum of all sources, kad: the max sources found
237 uint32_t differentNames = 0; // max known different names
238 uint32_t publishersKnown = 0; // max publishers known
239 uint32_t trustValue = 0; // average trust value
240 unsigned publishInfoTags = 0;
241 unsigned ratingCount = 0;
242 unsigned ratingTotal = 0;
243 CSearchResultList::const_iterator best = m_children.begin();
244 for (CSearchResultList::const_iterator it = m_children.begin(); it != m_children.end(); ++it) {
245 const CSearchFile* child = *it;
247 // Locate the most common name
248 if (child->GetSourceCount() > (*best)->GetSourceCount()) {
249 best = it;
252 // Sources
253 if (m_kademlia) {
254 sourceCount = std::max(sourceCount, child->m_sourceCount);
255 completeSourceCount = std::max(completeSourceCount, child->m_completeSourceCount);
256 } else {
257 sourceCount += child->m_sourceCount;
258 completeSourceCount += child->m_completeSourceCount;
261 // Publish info
262 if (child->GetKadPublishInfo() != 0) {
263 differentNames = std::max(differentNames, (child->GetKadPublishInfo() & 0xFF000000) >> 24);
264 publishersKnown = std::max(publishersKnown, (child->GetKadPublishInfo() & 0x00FF0000) >> 16);
265 trustValue += child->GetKadPublishInfo() & 0x0000FFFF;
266 publishInfoTags++;
269 // Rating
270 if (child->HasRating()) {
271 ratingCount++;
272 ratingTotal += child->UserRating();
275 // Available sources
276 if (child->GetClientID() && child->GetClientPort()) {
277 CSearchFile::ClientStruct client(child->GetClientID(), child->GetClientPort(), child->GetClientServerIP(), child->GetClientServerPort());
278 AddClient(client);
280 for (std::list<ClientStruct>::const_iterator cit = child->m_clients.begin(); cit != child->m_clients.end(); ++cit) {
281 AddClient(*cit);
285 m_sourceCount = sourceCount;
286 m_completeSourceCount = completeSourceCount;
288 if (publishInfoTags > 0) {
289 m_kadPublishInfo = ((differentNames & 0x000000FF) << 24) | ((publishersKnown & 0x000000FF) << 16) | ((trustValue / publishInfoTags) & 0x0000FFFF);
290 } else {
291 m_kadPublishInfo = 0;
294 if (ratingCount > 0) {
295 m_iUserRating = ratingTotal / ratingCount;
296 } else {
297 m_iUserRating = 0;
300 SetFileName((*best)->GetFileName());
303 void CSearchFile::SetDownloadStatus()
305 bool isPart = theApp->downloadqueue->GetFileByID(m_abyFileHash) != NULL;
306 bool isKnown = theApp->knownfiles->FindKnownFileByID(m_abyFileHash) != NULL;
307 bool isCanceled = theApp->canceledfiles->IsCanceledFile(m_abyFileHash);
309 if (isCanceled && isPart) {
310 m_downloadStatus = QUEUEDCANCELED;
311 } else if (isCanceled) {
312 m_downloadStatus = CANCELED;
313 } else if (isPart) {
314 m_downloadStatus = QUEUED;
315 } else if (isKnown) {
316 m_downloadStatus = DOWNLOADED;
317 } else {
318 m_downloadStatus = NEW;
320 // Update status of children too
321 for (CSearchResultList::iterator it = m_children.begin(); it != m_children.end(); it++) {
322 Notify_Search_Update_Sources(*it);
326 // File_checked_for_headers