Improve the code by static code analysis [3/3]: Style
[amule.git] / src / KnownFile.cpp
blob79608067c2e6d3297f3341c959b97834906132d7
1 //
2 // This file is part of the aMule Project.
3 //
4 // Parts of this file are based on work from pan One (http://home-3.tiscali.nl/~meost/pms/)
5 //
6 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
7 // Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
8 //
9 // Any parts of this program derived from the xMule, lMule or eMule project,
10 // or contributed by third-party developers are copyrighted by their
11 // respective authors.
13 // This program is free software; you can redistribute it and/or modify
14 // it under the terms of the GNU General Public License as published by
15 // the Free Software Foundation; either version 2 of the License, or
16 // (at your option) any later version.
18 // This program is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 // GNU General Public License for more details.
23 // You should have received a copy of the GNU General Public License
24 // along with this program; if not, write to the Free Software
25 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "KnownFile.h" // Do_not_auto_remove
31 #include <protocol/kad/Constants.h>
32 #include <protocol/ed2k/Client2Client/TCP.h>
33 #include <protocol/ed2k/ClientSoftware.h>
34 #include <protocol/Protocols.h>
35 #include <tags/FileTags.h>
37 #include <wx/config.h>
39 #ifdef CLIENT_GUI
40 #include "UpDownClientEC.h" // Needed for CUpDownClient
41 #else
42 #include "updownclient.h" // Needed for CUpDownClient
43 #endif
45 #include "MemFile.h" // Needed for CMemFile
46 #include "Packet.h" // Needed for CPacket
47 #include "Preferences.h" // Needed for CPreferences
48 #include "KnownFileList.h" // Needed for CKnownFileList
49 #include "amule.h" // Needed for theApp
50 #include "PartFile.h" // Needed for SavePartFile
51 #include "ClientList.h" // Needed for clientlist (buddy support)
52 #include "Logger.h"
53 #include "ScopedPtr.h" // Needed for CScopedArray and CScopedPtr
54 #include "GuiEvents.h" // Needed for Notify_*
55 #include "SearchFile.h" // Needed for CSearchFile
56 #include "FileArea.h" // Needed for CFileArea
57 #include "FileAutoClose.h" // Needed for CFileAutoClose
58 #include "Server.h" // Needed for CServer
60 #include "CryptoPP_Inc.h" // Needed for MD4
62 #include <common/Format.h>
64 CFileStatistic::CFileStatistic(CKnownFile *parent)
65 : fileParent(parent),
66 requested(0),
67 transferred(0),
68 accepted(0),
69 alltimerequested(0),
70 alltimetransferred(0),
71 alltimeaccepted(0)
74 #ifndef CLIENT_GUI
76 void CFileStatistic::AddRequest()
78 requested++;
79 alltimerequested++;
80 theApp->knownfiles->requested++;
81 theApp->sharedfiles->UpdateItem(fileParent);
84 void CFileStatistic::AddAccepted()
86 accepted++;
87 alltimeaccepted++;
88 theApp->knownfiles->accepted++;
89 theApp->sharedfiles->UpdateItem(fileParent);
92 void CFileStatistic::AddTransferred(uint64 bytes)
94 transferred += bytes;
95 alltimetransferred += bytes;
96 theApp->knownfiles->transferred += bytes;
97 theApp->sharedfiles->UpdateItem(fileParent);
100 #endif // CLIENT_GUI
103 /* Abstract File (base class)*/
105 CAbstractFile::CAbstractFile()
106 : m_iRating(0),
107 m_hasComment(false),
108 m_iUserRating(0),
109 m_nFileSize(0)
113 CAbstractFile::CAbstractFile(const CAbstractFile& other)
114 : m_abyFileHash(other.m_abyFileHash),
115 m_strComment(other.m_strComment),
116 m_iRating(other.m_iRating),
117 m_hasComment(other.m_hasComment),
118 m_iUserRating(other.m_iUserRating),
119 m_taglist(other.m_taglist),
120 m_kadNotes(),
121 m_nFileSize(other.m_nFileSize),
122 m_fileName(other.m_fileName)
124 /* // TODO: Currently it's not safe to duplicate the entries, but isn't needed either.
125 CKadEntryPtrList::const_iterator it = other.m_kadNotes.begin();
126 for (; it != other.m_kadNotes.end(); ++it) {
127 m_kadNotes.push_back(new Kademlia::CEntry(**it));
133 void CAbstractFile::SetFileName(const CPath& fileName)
135 m_fileName = fileName;
138 uint32 CAbstractFile::GetIntTagValue(uint8 tagname) const
140 ArrayOfCTag::const_iterator it = m_taglist.begin();
141 for (; it != m_taglist.end(); ++it){
142 if (((*it).GetNameID() == tagname) && (*it).IsInt()) {
143 return (*it).GetInt();
146 return 0;
149 bool CAbstractFile::GetIntTagValue(uint8 tagname, uint32& ruValue) const
151 ArrayOfCTag::const_iterator it = m_taglist.begin();
152 for (; it != m_taglist.end(); ++it){
153 if (((*it).GetNameID() == tagname) && (*it).IsInt()){
154 ruValue = (*it).GetInt();
155 return true;
158 return false;
161 uint32 CAbstractFile::GetIntTagValue(const wxString& tagname) const
163 ArrayOfCTag::const_iterator it = m_taglist.begin();
164 for (; it != m_taglist.end(); ++it){
165 if ((*it).IsInt() && ((*it).GetName() == tagname)) {
166 return (*it).GetInt();
169 return 0;
172 const wxString& CAbstractFile::GetStrTagValue(uint8 tagname) const
174 ArrayOfCTag::const_iterator it = m_taglist.begin();
175 for (; it != m_taglist.end(); ++it){
176 if ((*it).GetNameID() == tagname && (*it).IsStr()) {
177 return (*it).GetStr();
180 return EmptyString;
183 const wxString& CAbstractFile::GetStrTagValue(const wxString& tagname) const
185 ArrayOfCTag::const_iterator it = m_taglist.begin();
186 for (; it != m_taglist.end(); ++it){
187 if ((*it).IsStr() && ((*it).GetName() == tagname)) {
188 return (*it).GetStr();
191 return EmptyString;
194 const CTag *CAbstractFile::GetTag(uint8 tagname, uint8 tagtype) const
196 ArrayOfCTag::const_iterator it = m_taglist.begin();
197 for (; it != m_taglist.end(); ++it){
198 if ((*it).GetNameID() == tagname && (*it).GetType() == tagtype) {
199 return &(*it);
202 return NULL;
205 const CTag *CAbstractFile::GetTag(const wxString& tagname, uint8 tagtype) const
207 ArrayOfCTag::const_iterator it = m_taglist.begin();
208 for (; it != m_taglist.end(); ++it){
209 if ((*it).GetType() == tagtype && (*it).GetName() == tagname) {
210 return &(*it);
213 return NULL;
216 const CTag *CAbstractFile::GetTag(uint8 tagname) const
218 ArrayOfCTag::const_iterator it = m_taglist.begin();
219 for (; it != m_taglist.end(); ++it){
220 if ((*it).GetNameID() == tagname) {
221 return &(*it);
224 return NULL;
227 const CTag *CAbstractFile::GetTag(const wxString& tagname) const
229 ArrayOfCTag::const_iterator it = m_taglist.begin();
230 for (; it != m_taglist.end(); ++it){
231 if ((*it).GetName() == tagname) {
232 return &(*it);
235 return NULL;
238 void CAbstractFile::AddTagUnique(const CTag &rTag)
240 ArrayOfCTag::iterator it = m_taglist.begin();
241 for (; it != m_taglist.end(); ++it) {
242 if ( ( ((*it).GetNameID() != 0 &&
243 (*it).GetNameID() == rTag.GetNameID()) ||
244 (!(*it).GetName().IsEmpty() &&
245 !rTag.GetName().IsEmpty() &&
246 (*it).GetName() == rTag.GetName()) ) &&
247 (*it).GetType() == rTag.GetType())
249 it = m_taglist.erase(it);
250 m_taglist.insert(it, rTag);
251 return;
254 m_taglist.push_back(rTag);
257 #ifndef CLIENT_GUI
258 void CAbstractFile::AddNote(Kademlia::CEntry *pEntry)
260 CKadEntryPtrList::iterator it = m_kadNotes.begin();
261 for (; it != m_kadNotes.end(); ++it) {
262 Kademlia::CEntry* entry = *it;
263 if(entry->m_uIP == pEntry->m_uIP || entry->m_uSourceID == pEntry->m_uSourceID) {
264 delete pEntry;
265 return;
268 m_kadNotes.push_front(pEntry);
270 #else
271 void CAbstractFile::AddNote(Kademlia::CEntry *)
274 #endif
277 /* Known File */
279 CKnownFile::CKnownFile()
280 : statistic(this)
282 Init();
285 CKnownFile::CKnownFile(uint32 ecid)
286 : CECID(ecid),
287 statistic(this)
289 Init();
293 //#warning Experimental: Construct a CKnownFile from a CSearchFile
294 CKnownFile::CKnownFile(const CSearchFile &searchFile)
296 // This will copy the file hash
297 CAbstractFile(static_cast<const CAbstractFile &>(searchFile)),
298 statistic(this)
300 Init();
302 // Use CKnownFile::SetFileName()
303 SetFileName(searchFile.GetFileName());
305 // Use CKnownFile::SetFileSize()
306 SetFileSize(searchFile.GetFileSize());
310 void CKnownFile::Init()
312 m_showSources = false;
313 m_showPeers = false;
314 m_nCompleteSourcesTime = time(NULL);
315 m_nCompleteSourcesCount = 0;
316 m_nCompleteSourcesCountLo = 0;
317 m_nCompleteSourcesCountHi = 0;
318 m_bCommentLoaded = false;
319 m_iPartCount = 0;
320 m_iED2KPartCount = 0;
321 m_iED2KPartHashCount = 0;
322 m_PublishedED2K = false;
323 kadFileSearchID = 0;
324 m_lastPublishTimeKadSrc = 0;
325 m_lastPublishTimeKadNotes = 0;
326 m_lastBuddyIP = 0;
327 m_lastDateChanged = 0;
328 m_bAutoUpPriority = thePrefs::GetNewAutoUp();
329 m_iUpPriority = ( m_bAutoUpPriority ) ? PR_HIGH : PR_NORMAL;
330 m_hashingProgress = 0;
332 #ifndef CLIENT_GUI
333 m_pAICHHashSet = new CAICHHashSet(this);
334 #endif
338 void CKnownFile::SetFileSize(uint64 nFileSize)
340 CAbstractFile::SetFileSize(nFileSize);
341 #ifndef CLIENT_GUI
342 m_pAICHHashSet->SetFileSize(nFileSize);
343 #endif
345 // Examples of parthashs, hashsets and filehashs for different filesizes
346 // according the ed2k protocol
347 //----------------------------------------------------------------------
349 //File size: 3 bytes
350 //File hash: 2D55E87D0E21F49B9AD25F98531F3724
351 //Nr. hashs: 0
354 //File size: 1*PARTSIZE
355 //File hash: A72CA8DF7F07154E217C236C89C17619
356 //Nr. hashs: 2
357 //Hash[ 0]: 4891ED2E5C9C49F442145A3A5F608299
358 //Hash[ 1]: 31D6CFE0D16AE931B73C59D7E0C089C0 *special part hash*
361 //File size: 1*PARTSIZE + 1 byte
362 //File hash: 2F620AE9D462CBB6A59FE8401D2B3D23
363 //Nr. hashs: 2
364 //Hash[ 0]: 121795F0BEDE02DDC7C5426D0995F53F
365 //Hash[ 1]: C329E527945B8FE75B3C5E8826755747
368 //File size: 2*PARTSIZE
369 //File hash: A54C5E562D5E03CA7D77961EB9A745A4
370 //Nr. hashs: 3
371 //Hash[ 0]: B3F5CE2A06BF403BFB9BFFF68BDDC4D9
372 //Hash[ 1]: 509AA30C9EA8FC136B1159DF2F35B8A9
373 //Hash[ 2]: 31D6CFE0D16AE931B73C59D7E0C089C0 *special part hash*
376 //File size: 3*PARTSIZE
377 //File hash: 5E249B96F9A46A18FC2489B005BF2667
378 //Nr. hashs: 4
379 //Hash[ 0]: 5319896A2ECAD43BF17E2E3575278E72
380 //Hash[ 1]: D86EF157D5E49C5ED502EDC15BB5F82B
381 //Hash[ 2]: 10F2D5B1FCB95C0840519C58D708480F
382 //Hash[ 3]: 31D6CFE0D16AE931B73C59D7E0C089C0 *special part hash*
385 //File size: 3*PARTSIZE + 1 byte
386 //File hash: 797ED552F34380CAFF8C958207E40355
387 //Nr. hashs: 4
388 //Hash[ 0]: FC7FD02CCD6987DCF1421F4C0AF94FB8
389 //Hash[ 1]: 2FE466AF8A7C06DA3365317B75A5ACFE
390 //Hash[ 2]: 873D3BF52629F7C1527C6E8E473C1C30
391 //Hash[ 3]: BCE50BEE7877BB07BB6FDA56BFE142FB
394 // File size Data parts ED2K parts ED2K part hashs
395 // ---------------------------------------------------------------
396 // 1..PARTSIZE-1 1 1 0(!)
397 // PARTSIZE 1 2(!) 2(!)
398 // PARTSIZE+1 2 2 2
399 // PARTSIZE*2 2 3(!) 3(!)
400 // PARTSIZE*2+1 3 3 3
402 if (nFileSize == 0){
403 //wxFAIL; // Kry - Why commented out by lemonfan? it can never be 0
404 m_iPartCount = 0;
405 m_iED2KPartCount = 0;
406 m_iED2KPartHashCount = 0;
407 m_sizeLastPart = 0;
408 return;
411 // nr. of data parts
412 m_iPartCount = nFileSize / PARTSIZE + 1;
413 // size of last part
414 m_sizeLastPart = nFileSize % PARTSIZE;
415 // file with size of n * PARTSIZE
416 if (m_sizeLastPart == 0) {
417 m_sizeLastPart = PARTSIZE;
418 m_iPartCount--;
421 // nr. of parts to be used with OP_FILESTATUS
422 m_iED2KPartCount = nFileSize / PARTSIZE + 1;
424 // nr. of parts to be used with OP_HASHSETANSWER
425 m_iED2KPartHashCount = nFileSize / PARTSIZE;
426 if (m_iED2KPartHashCount != 0) {
427 m_iED2KPartHashCount += 1;
432 void CKnownFile::AddUploadingClient(CUpDownClient* client)
434 m_ClientUploadList.insert(CCLIENTREF(client, wxT("CKnownFile::AddUploadingClient m_ClientUploadList")));
436 SourceItemType type = UNAVAILABLE_SOURCE;
437 switch (client->GetUploadState()) {
438 case US_UPLOADING:
439 case US_ONUPLOADQUEUE:
440 type = AVAILABLE_SOURCE;
441 break;
442 default: {
443 // Any other state is UNAVAILABLE_SOURCE by default.
447 Notify_SharedCtrlAddClient(this, CCLIENTREF(client, wxT("CKnownFile::AddUploadingClient Notify_SharedCtrlAddClient")), type);
449 UpdateAutoUpPriority();
453 void CKnownFile::RemoveUploadingClient(CUpDownClient* client)
455 if (m_ClientUploadList.erase(CCLIENTREF(client, wxEmptyString))) {
456 Notify_SharedCtrlRemoveClient(client->ECID(), this);
457 UpdateAutoUpPriority();
462 #ifdef CLIENT_GUI
464 CKnownFile::CKnownFile(const CEC_SharedFile_Tag *tag)
465 : CECID(tag->ID()),
466 statistic(this)
468 Init();
470 m_abyFileHash = tag->FileHash();
471 SetFileSize(tag->SizeFull());
472 m_AvailPartFrequency.insert(m_AvailPartFrequency.end(), m_iPartCount, 0);
473 m_queuedCount = 0;
476 CKnownFile::~CKnownFile()
479 void CKnownFile::UpdateAutoUpPriority()
483 #else // ! CLIENT_GUI
485 CKnownFile::~CKnownFile()
487 SourceSet::iterator it = m_ClientUploadList.begin();
488 for ( ; it != m_ClientUploadList.end(); ++it ) {
489 it->ClearUploadFileID();
492 delete m_pAICHHashSet;
496 void CKnownFile::SetFilePath(const CPath& filePath)
498 m_filePath = filePath;
502 // needed for memfiles. its probably better to switch everything to CFile...
503 bool CKnownFile::LoadHashsetFromFile(const CFileDataIO* file, bool checkhash)
505 CMD4Hash checkid = file->ReadHash();
507 uint16 parts = file->ReadUInt16();
508 m_hashlist.clear();
509 for (uint16 i = 0; i < parts; ++i){
510 CMD4Hash cur_hash = file->ReadHash();
511 m_hashlist.push_back(cur_hash);
514 // SLUGFILLER: SafeHash - always check for valid m_hashlist
515 if (!checkhash){
516 m_abyFileHash = checkid;
517 if (parts <= 1) { // nothing to check
518 return true;
520 } else {
521 if ( m_abyFileHash != checkid ) {
522 return false; // wrong file?
523 } else {
524 if (parts != GetED2KPartHashCount()) {
525 return false;
529 // SLUGFILLER: SafeHash
531 // trust noone ;-)
532 // lol, useless comment but made me lmao
533 // wtf you guys are weird.
535 if (!m_hashlist.empty()) {
536 CreateHashFromHashlist(m_hashlist, &checkid);
539 if ( m_abyFileHash == checkid ) {
540 return true;
541 } else {
542 m_hashlist.clear();
543 return false;
548 bool CKnownFile::LoadTagsFromFile(const CFileDataIO* file)
550 uint32 tagcount = file->ReadUInt32();
551 m_taglist.clear();
552 for (uint32 j = 0; j != tagcount; ++j) {
553 CTag newtag(*file, true);
554 switch(newtag.GetNameID()){
555 case FT_FILENAME:
556 if (GetFileName().IsOk()) {
557 // Unlike eMule, we actually prefer the second
558 // filename tag, since we use it to specify the
559 // 'universial' filename (see CPath::ToUniv).
560 CPath path = CPath::FromUniv(newtag.GetStr());
562 // May be invalid, if from older versions where
563 // unicoded filenames be saved as empty-strings.
564 if (path.IsOk()) {
565 SetFileName(path);
567 } else {
568 SetFileName(CPath(newtag.GetStr()));
570 break;
572 case FT_FILESIZE:
573 SetFileSize(newtag.GetInt());
574 m_AvailPartFrequency.clear();
575 m_AvailPartFrequency.insert(
576 m_AvailPartFrequency.begin(),
577 GetPartCount(), 0);
578 break;
580 case FT_ATTRANSFERRED:
581 statistic.SetAllTimeTransferred(statistic.GetAllTimeTransferred() + newtag.GetInt());
582 break;
584 case FT_ATTRANSFERREDHI:
585 statistic.SetAllTimeTransferred(statistic.GetAllTimeTransferred() + (((uint64)newtag.GetInt()) << 32));
586 break;
588 case FT_ATREQUESTED:
589 statistic.SetAllTimeRequests(newtag.GetInt());
590 break;
592 case FT_ATACCEPTED:
593 statistic.SetAllTimeAccepts(newtag.GetInt());
594 break;
596 case FT_ULPRIORITY:
597 m_iUpPriority = newtag.GetInt();
598 if( m_iUpPriority == PR_AUTO ){
599 m_iUpPriority = PR_HIGH;
600 m_bAutoUpPriority = true;
601 } else {
602 if ( m_iUpPriority != PR_VERYLOW &&
603 m_iUpPriority != PR_LOW &&
604 m_iUpPriority != PR_NORMAL &&
605 m_iUpPriority != PR_HIGH &&
606 m_iUpPriority != PR_VERYHIGH &&
607 m_iUpPriority != PR_POWERSHARE) {
608 m_iUpPriority = PR_NORMAL;
611 m_bAutoUpPriority = false;
613 break;
615 case FT_PERMISSIONS:
616 // Ignore it, it's not used anymore.
617 break;
619 case FT_AICH_HASH: {
620 CAICHHash hash;
621 bool hashSizeOk =
622 hash.DecodeBase32(newtag.GetStr()) == CAICHHash::GetHashSize();
623 wxASSERT(hashSizeOk);
624 if (hashSizeOk) {
625 m_pAICHHashSet->SetMasterHash(hash, AICH_HASHSETCOMPLETE);
627 break;
630 case FT_KADLASTPUBLISHSRC:
631 SetLastPublishTimeKadSrc( newtag.GetInt(), 0 );
633 if(GetLastPublishTimeKadSrc() > (uint32)time(NULL)+KADEMLIAREPUBLISHTIMES) {
634 //There may be a posibility of an older client that saved a random number here.. This will check for that..
635 SetLastPublishTimeKadSrc(0, 0);
637 break;
639 case FT_KADLASTPUBLISHNOTES:
640 SetLastPublishTimeKadNotes( newtag.GetInt() );
641 break;
643 case FT_KADLASTPUBLISHKEY:
644 // Just purge it
645 wxASSERT( newtag.IsInt() );
646 break;
648 default:
649 // Store them here and write them back on saving.
650 m_taglist.push_back(newtag);
654 return true;
658 bool CKnownFile::LoadDateFromFile(const CFileDataIO* file)
660 m_lastDateChanged = file->ReadUInt32();
662 return true;
666 bool CKnownFile::LoadFromFile(const CFileDataIO* file)
668 // SLUGFILLER: SafeHash - load first, verify later
669 bool ret1 = LoadDateFromFile(file);
670 bool ret2 = LoadHashsetFromFile(file,false);
671 bool ret3 = LoadTagsFromFile(file);
672 UpdatePartsInfo();
673 // Final hash-count verification, needs to be done after the tags are loaded.
674 return ret1 && ret2 && ret3 && GetED2KPartHashCount()==GetHashCount();
675 // SLUGFILLER: SafeHash
679 bool CKnownFile::WriteToFile(CFileDataIO* file)
681 wxCHECK(!IsPartFile(), false);
683 // date
684 file->WriteUInt32(m_lastDateChanged);
685 // hashset
686 file->WriteHash(m_abyFileHash);
688 uint16 parts = m_hashlist.size();
689 file->WriteUInt16(parts);
691 for (int i = 0; i < parts; ++i)
692 file->WriteHash(m_hashlist[i]);
694 //tags
695 const int iFixedTags = 8;
696 uint32 tagcount = iFixedTags;
697 if (HasProperAICHHashSet()) {
698 tagcount++;
700 // Float meta tags are currently not written. All older eMule versions < 0.28a have
701 // a bug in the meta tag reading+writing code. To achive maximum backward
702 // compatibility for met files with older eMule versions we just don't write float
703 // tags. This is OK, because we (eMule) do not use float tags. The only float tags
704 // we may have to handle is the '# Sent' tag from the Hybrid, which is pretty
705 // useless but may be received from us via the servers.
707 // The code for writing the float tags SHOULD BE ENABLED in SOME MONTHS (after most
708 // people are using the newer eMule versions which do not write broken float tags).
709 for (size_t j = 0; j < m_taglist.size(); ++j){
710 if (m_taglist[j].IsInt() || m_taglist[j].IsStr()) {
711 ++tagcount;
715 if (m_lastPublishTimeKadSrc) {
716 ++tagcount;
719 if (m_lastPublishTimeKadNotes){
720 ++tagcount;
723 // standard tags
725 file->WriteUInt32(tagcount);
727 // We still save the unicoded filename, for backwards
728 // compatibility with pre-2.2 and other clients.
729 CTagString nametag_unicode(FT_FILENAME, GetFileName().GetRaw());
730 // We write it with BOM to keep eMule compatibility
731 nametag_unicode.WriteTagToFile(file,utf8strOptBOM);
733 // The non-unicoded filename is written in an 'universial'
734 // format, which allows us to identify files, even if the
735 // system locale changes.
736 CTagString nametag(FT_FILENAME, CPath::ToUniv(GetFileName()));
737 nametag.WriteTagToFile(file);
739 CTagIntSized sizetag(FT_FILESIZE, GetFileSize(), IsLargeFile() ? 64 : 32);
740 sizetag.WriteTagToFile(file);
742 // statistic
743 uint32 tran;
744 tran = statistic.GetAllTimeTransferred() & 0xFFFFFFFF;
745 CTagInt32 attag1(FT_ATTRANSFERRED, tran);
746 attag1.WriteTagToFile(file);
748 tran = statistic.GetAllTimeTransferred() >> 32;
749 CTagInt32 attag4(FT_ATTRANSFERREDHI, tran);
750 attag4.WriteTagToFile(file);
752 CTagInt32 attag2(FT_ATREQUESTED, statistic.GetAllTimeRequests());
753 attag2.WriteTagToFile(file);
755 CTagInt32 attag3(FT_ATACCEPTED, statistic.GetAllTimeAccepts());
756 attag3.WriteTagToFile(file);
758 // priority N permission
759 CTagInt32 priotag(FT_ULPRIORITY, IsAutoUpPriority() ? PR_AUTO : m_iUpPriority);
760 priotag.WriteTagToFile(file);
762 //AICH Filehash
763 if (HasProperAICHHashSet()) {
764 CTagString aichtag(FT_AICH_HASH, m_pAICHHashSet->GetMasterHash().GetString());
765 aichtag.WriteTagToFile(file);
768 // Kad sources
769 if (m_lastPublishTimeKadSrc){
770 CTagInt32 kadLastPubSrc(FT_KADLASTPUBLISHSRC, m_lastPublishTimeKadSrc);
771 kadLastPubSrc.WriteTagToFile(file);
774 // Kad notes
775 if (m_lastPublishTimeKadNotes){
776 CTagInt32 kadLastPubNotes(FT_KADLASTPUBLISHNOTES, m_lastPublishTimeKadNotes);
777 kadLastPubNotes.WriteTagToFile(file);
780 //other tags
781 for (size_t j = 0; j < m_taglist.size(); ++j){
782 if (m_taglist[j].IsInt() || m_taglist[j].IsStr()) {
783 m_taglist[j].WriteTagToFile(file);
786 return true;
790 void CKnownFile::CreateHashFromHashlist(const ArrayOfCMD4Hash& hashes, CMD4Hash* Output)
792 wxCHECK_RET(hashes.size(), wxT("No input to hash from in CreateHashFromHashlist"));
794 std::vector<byte> buffer(hashes.size() * MD4HASH_LENGTH);
795 std::vector<byte>::iterator it = buffer.begin();
797 for (size_t i = 0; i < hashes.size(); ++i) {
798 it = STLCopy_n(hashes[i].GetHash(), MD4HASH_LENGTH, it);
801 CreateHashFromInput(&buffer[0], buffer.size(), Output, NULL);
805 void CKnownFile::CreateHashFromFile(CFileAutoClose& file, uint64 offset, uint32 Length, CMD4Hash* Output, CAICHHashTree* pShaHashOut)
807 wxCHECK_RET(Length, wxT("No input to hash from in CreateHashFromFile"));
809 CFileArea area;
810 area.ReadAt(file, offset, Length);
812 CreateHashFromInput(area.GetBuffer(), Length, Output, pShaHashOut);
813 area.CheckError();
817 void CKnownFile::CreateHashFromInput(const byte* input, uint32 Length, CMD4Hash* Output, CAICHHashTree* pShaHashOut )
819 wxASSERT_MSG(Output || pShaHashOut, wxT("Nothing to do in CreateHashFromInput"));
820 { wxCHECK_RET(input, wxT("No input to hash from in CreateHashFromInput")); }
821 wxASSERT(Length <= PARTSIZE); // We never hash more than one PARTSIZE
823 CMemFile data(input, Length);
825 uint32 Required = Length;
826 byte X[64*128];
828 uint32 posCurrentEMBlock = 0;
829 uint32 nIACHPos = 0;
830 CScopedPtr<CAICHHashAlgo> pHashAlg(CAICHHashSet::GetNewHashAlgo());
832 // This is all AICH.
833 while (Required >= 64) {
834 uint32 len = Required / 64;
835 if (len > sizeof(X)/(64 * sizeof(X[0]))) {
836 len = sizeof(X)/(64 * sizeof(X[0]));
839 data.Read(&X, len * 64);
841 // SHA hash needs 180KB blocks
842 if (pShaHashOut) {
843 if (nIACHPos + len*64 >= EMBLOCKSIZE) {
844 uint32 nToComplete = EMBLOCKSIZE - nIACHPos;
845 pHashAlg->Add(X, nToComplete);
846 wxASSERT( nIACHPos + nToComplete == EMBLOCKSIZE );
847 pShaHashOut->SetBlockHash(EMBLOCKSIZE, posCurrentEMBlock, pHashAlg.get());
848 posCurrentEMBlock += EMBLOCKSIZE;
849 pHashAlg->Reset();
850 pHashAlg->Add(X+nToComplete,(len*64) - nToComplete);
851 nIACHPos = (len*64) - nToComplete;
853 else{
854 pHashAlg->Add(X, len*64);
855 nIACHPos += len*64;
859 Required -= len*64;
861 // bytes to read
862 Required = Length % 64;
863 if (Required != 0){
864 data.Read(&X,Required);
866 if (pShaHashOut != NULL){
867 if (nIACHPos + Required >= EMBLOCKSIZE){
868 uint32 nToComplete = EMBLOCKSIZE - nIACHPos;
869 pHashAlg->Add(X, nToComplete);
870 wxASSERT( nIACHPos + nToComplete == EMBLOCKSIZE );
871 pShaHashOut->SetBlockHash(EMBLOCKSIZE, posCurrentEMBlock, pHashAlg.get());
872 posCurrentEMBlock += EMBLOCKSIZE;
873 pHashAlg->Reset();
874 pHashAlg->Add(X+nToComplete, Required - nToComplete);
875 nIACHPos = Required - nToComplete;
877 else{
878 pHashAlg->Add(X, Required);
879 nIACHPos += Required;
883 if (pShaHashOut != NULL){
884 if(nIACHPos > 0){
885 pShaHashOut->SetBlockHash(nIACHPos, posCurrentEMBlock, pHashAlg.get());
886 posCurrentEMBlock += nIACHPos;
888 wxASSERT( posCurrentEMBlock == Length );
889 wxCHECK2( pShaHashOut->ReCalculateHash(pHashAlg.get(), false), );
892 if (Output != NULL){
893 #ifdef __WEAK_CRYPTO__
894 CryptoPP::Weak::MD4 md4_hasher;
895 #else
896 CryptoPP::MD4 md4_hasher;
897 #endif
898 md4_hasher.CalculateDigest(Output->GetHash(), input, Length);
903 const CMD4Hash& CKnownFile::GetPartHash(uint16 part) const {
904 wxASSERT( part < m_hashlist.size() );
906 return m_hashlist[part];
909 CPacket* CKnownFile::CreateSrcInfoPacket(const CUpDownClient* forClient, uint8 byRequestedVersion, uint16 nRequestedOptions)
911 // Kad reviewed
913 if (m_ClientUploadList.empty()) {
914 return NULL;
917 if (((static_cast<CKnownFile*>(forClient->GetRequestFile()) != this)
918 && (forClient->GetUploadFile() != this)) || forClient->GetUploadFileID() != GetFileHash()) {
919 wxString file1 = _("Unknown");
920 if (forClient->GetRequestFile() && forClient->GetRequestFile()->GetFileName().IsOk()) {
921 file1 = forClient->GetRequestFile()->GetFileName().GetPrintable();
922 } else if (forClient->GetUploadFile() && forClient->GetUploadFile()->GetFileName().IsOk()) {
923 file1 = forClient->GetUploadFile()->GetFileName().GetPrintable();
925 wxString file2 = _("Unknown");
926 if (GetFileName().IsOk()) {
927 file2 = GetFileName().GetPrintable();
929 AddDebugLogLineN(logKnownFiles, wxT("File mismatch on source packet (K) Sending: ") + file1 + wxT(" From: ") + file2);
930 return NULL;
933 const BitVector& rcvstatus = forClient->GetUpPartStatus();
934 bool SupportsUploadChunksState = !rcvstatus.empty();
935 //wxASSERT(rcvstatus.size() == GetPartCount()); // Obviously!
936 if (rcvstatus.size() != GetPartCount()) {
937 // Yuck. Same file but different part count? Seriously fucked up.
938 AddDebugLogLineN(logKnownFiles, CFormat(wxT("Impossible situation: different partcounts for the same known file: %i (client) and %i (file)")) % rcvstatus.size() % GetPartCount());
939 return NULL;
942 CMemFile data(1024);
944 uint8 byUsedVersion;
945 bool bIsSX2Packet;
946 if (forClient->SupportsSourceExchange2() && byRequestedVersion > 0){
947 // the client uses SourceExchange2 and requested the highest version he knows
948 // and we send the highest version we know, but of course not higher than his request
949 byUsedVersion = std::min(byRequestedVersion, (uint8)SOURCEEXCHANGE2_VERSION);
950 bIsSX2Packet = true;
951 data.WriteUInt8(byUsedVersion);
953 // we don't support any special SX2 options yet, reserved for later use
954 if (nRequestedOptions != 0) {
955 AddDebugLogLineN(logKnownFiles, CFormat(wxT("Client requested unknown options for SourceExchange2: %u")) % nRequestedOptions);
957 } else {
958 byUsedVersion = forClient->GetSourceExchange1Version();
959 bIsSX2Packet = false;
960 if (forClient->SupportsSourceExchange2()) {
961 AddDebugLogLineN(logKnownFiles, wxT("Client which announced to support SX2 sent SX1 packet instead"));
965 uint16 nCount = 0;
967 data.WriteHash(forClient->GetUploadFileID());
968 data.WriteUInt16(nCount);
969 uint32 cDbgNoSrc = 0;
971 SourceSet::iterator it = m_ClientUploadList.begin();
972 for ( ; it != m_ClientUploadList.end(); ++it ) {
973 const CUpDownClient *cur_src = it->GetClient();
975 if ( cur_src->HasLowID() ||
976 cur_src == forClient ||
977 !( cur_src->GetUploadState() == US_UPLOADING ||
978 cur_src->GetUploadState() == US_ONUPLOADQUEUE)) {
979 continue;
982 bool bNeeded = false;
984 if ( SupportsUploadChunksState ) {
985 const BitVector& srcstatus = cur_src->GetUpPartStatus();
986 if ( !srcstatus.empty() ) {
987 //wxASSERT(srcstatus.size() == GetPartCount()); // Obviously!
988 if (srcstatus.size() != GetPartCount()) {
989 continue;
991 if ( cur_src->GetUpPartCount() == forClient->GetUpPartCount() ) {
992 for (int x = 0; x < GetPartCount(); x++ ) {
993 if ( srcstatus.get(x) && !rcvstatus.get(x) ) {
994 // We know the receiving client needs
995 // a chunk from this client.
996 bNeeded = true;
997 break;
1001 } else {
1002 cDbgNoSrc++;
1003 // This client doesn't support upload chunk status.
1004 // So just send it and hope for the best.
1005 bNeeded = true;
1007 } else {
1008 // remote client does not support upload chunk status,
1009 // search sources which have at least one complete part
1010 // we could even sort the list of sources by available
1011 // chunks to return as much sources as possible which
1012 // have the most available chunks. but this could be
1013 // a noticeable performance problem.
1014 const BitVector& srcstatus = cur_src->GetUpPartStatus();
1015 if ( !srcstatus.empty() ) {
1016 //wxASSERT(srcstatus.size() == GetPartCount());
1017 if (srcstatus.size() != GetPartCount()) {
1018 continue;
1020 for (int x = 0; x < GetPartCount(); x++ ) {
1021 if ( srcstatus.get(x) ) {
1022 // this client has at least one chunk
1023 bNeeded = true;
1024 break;
1027 } else {
1028 // This client doesn't support upload chunk status.
1029 // So just send it and hope for the best.
1030 bNeeded = true;
1034 if ( bNeeded ) {
1035 nCount++;
1036 uint32 dwID;
1037 if(byUsedVersion >= 3) {
1038 dwID = cur_src->GetUserIDHybrid();
1039 } else {
1040 dwID = cur_src->GetIP();
1042 data.WriteUInt32(dwID);
1043 data.WriteUInt16(cur_src->GetUserPort());
1044 data.WriteUInt32(cur_src->GetServerIP());
1045 data.WriteUInt16(cur_src->GetServerPort());
1047 if (byUsedVersion >= 2) {
1048 data.WriteHash(cur_src->GetUserHash());
1051 if (byUsedVersion >= 4){
1052 // CryptSettings - SourceExchange V4
1053 // 5 Reserved (!)
1054 // 1 CryptLayer Required
1055 // 1 CryptLayer Requested
1056 // 1 CryptLayer Supported
1057 const uint8 uSupportsCryptLayer = cur_src->SupportsCryptLayer() ? 1 : 0;
1058 const uint8 uRequestsCryptLayer = cur_src->RequestsCryptLayer() ? 1 : 0;
1059 const uint8 uRequiresCryptLayer = cur_src->RequiresCryptLayer() ? 1 : 0;
1060 const uint8 byCryptOptions = (uRequiresCryptLayer << 2) | (uRequestsCryptLayer << 1) | (uSupportsCryptLayer << 0);
1061 data.WriteUInt8(byCryptOptions);
1064 if (nCount > 500) {
1065 break;
1070 if (!nCount) {
1071 return 0;
1074 data.Seek(bIsSX2Packet ? 17 : 16, wxFromStart);
1075 data.WriteUInt16(nCount);
1077 CPacket* result = new CPacket(data, OP_EMULEPROT, bIsSX2Packet ? OP_ANSWERSOURCES2 : OP_ANSWERSOURCES);
1079 if ( result->GetPacketSize() > 354 ) {
1080 result->PackPacket();
1083 return result;
1087 void CKnownFile::CreateOfferedFilePacket(
1088 CMemFile *files,
1089 CServer *pServer,
1090 CUpDownClient *pClient) {
1092 // This function is used for offering files to the local server and for sending
1093 // shared files to some other client. In each case we send our IP+Port only, if
1094 // we have a HighID.
1096 wxASSERT(!(pClient && pServer));
1098 SetPublishedED2K(true);
1099 files->WriteHash(GetFileHash());
1101 uint32 nClientID = 0;
1102 uint16 nClientPort = 0;
1104 if (pServer) {
1105 if (pServer->GetTCPFlags() & SRV_TCPFLG_COMPRESSION) {
1106 #define FILE_COMPLETE_ID 0xfbfbfbfb
1107 #define FILE_COMPLETE_PORT 0xfbfb
1108 #define FILE_INCOMPLETE_ID 0xfcfcfcfc
1109 #define FILE_INCOMPLETE_PORT 0xfcfc
1110 // complete file: ip 251.251.251 (0xfbfbfbfb) port 0xfbfb
1111 // incomplete file: op 252.252.252 (0xfcfcfcfc) port 0xfcfc
1112 if (GetStatus() == PS_COMPLETE) {
1113 nClientID = FILE_COMPLETE_ID;
1114 nClientPort = FILE_COMPLETE_PORT;
1115 } else {
1116 nClientID = FILE_INCOMPLETE_ID;
1117 nClientPort = FILE_INCOMPLETE_PORT;
1119 } else {
1120 if (theApp->IsConnectedED2K() && !::IsLowID(theApp->GetED2KID())){
1121 nClientID = theApp->GetID();
1122 nClientPort = thePrefs::GetPort();
1125 } else {
1126 // Do not merge this with the above case - this one
1127 // also checks Kad status.
1128 if (theApp->IsConnected() && !theApp->IsFirewalled()) {
1129 nClientID = theApp->GetID();
1130 nClientPort = thePrefs::GetPort();
1134 files->WriteUInt32(nClientID);
1135 files->WriteUInt16(nClientPort);
1137 TagPtrList tags;
1139 // The printable filename is used because it's destined for another user.
1140 tags.push_back(new CTagString(FT_FILENAME, GetFileName().GetPrintable()));
1142 if (pClient && pClient->GetVBTTags()) {
1143 tags.push_back(new CTagVarInt(FT_FILESIZE, GetFileSize()));
1144 } else {
1145 if (!IsLargeFile()){
1146 tags.push_back(new CTagInt32(FT_FILESIZE, GetFileSize()));
1147 } else {
1148 // Large file
1149 // we send 2*32 bit tags to servers, but a real 64 bit tag to other clients.
1150 if (pServer) {
1151 if (!pServer->SupportsLargeFilesTCP()){
1152 wxFAIL;
1153 tags.push_back(new CTagInt32(FT_FILESIZE, 0));
1154 } else {
1155 tags.push_back(new CTagInt32(FT_FILESIZE, (uint32)GetFileSize()));
1156 tags.push_back(new CTagInt32(FT_FILESIZE_HI, (uint32)(GetFileSize() >> 32)));
1158 } else {
1159 if (!pClient->SupportsLargeFiles()) {
1160 wxFAIL;
1161 tags.push_back(new CTagInt32(FT_FILESIZE, 0));
1162 } else {
1163 tags.push_back(new CTagInt64(FT_FILESIZE, GetFileSize()));
1169 if (GetFileRating()) {
1170 tags.push_back(new CTagVarInt(FT_FILERATING, GetFileRating(), (pClient && pClient->GetVBTTags()) ? 0 : 32));
1173 // NOTE: Archives and CD-Images are published+searched with file type "Pro"
1174 bool bAddedFileType = false;
1175 if (pServer && (pServer->GetTCPFlags() & SRV_TCPFLG_TYPETAGINTEGER)) {
1176 // Send integer file type tags to newer servers
1177 EED2KFileType eFileType = GetED2KFileTypeSearchID(GetED2KFileTypeID(GetFileName()));
1178 if (eFileType >= ED2KFT_AUDIO && eFileType <= ED2KFT_CDIMAGE) {
1179 tags.push_back(new CTagInt32(FT_FILETYPE, eFileType));
1180 bAddedFileType = true;
1183 if (!bAddedFileType) {
1184 // Send string file type tags to:
1185 // - newer servers, in case there is no integer type available for the file type (e.g. emulecollection)
1186 // - older servers
1187 // - all clients
1188 wxString strED2KFileType(GetED2KFileTypeSearchTerm(GetED2KFileTypeID(GetFileName())));
1189 if (!strED2KFileType.IsEmpty()) {
1190 tags.push_back(new CTagString(FT_FILETYPE, strED2KFileType));
1194 // There, we could add MetaData info, if we ever get to have that.
1196 EUtf8Str eStrEncode;
1198 bool unicode_support =
1199 // eservers that support UNICODE.
1200 (pServer && (pServer->GetUnicodeSupport()))
1202 // clients that support unicode
1203 (pClient && pClient->GetUnicodeSupport());
1204 eStrEncode = unicode_support ? utf8strRaw : utf8strNone;
1206 files->WriteUInt32(tags.size());
1208 // Sadly, eMule doesn't use a MISCOPTIONS flag on hello packet for this, so we
1209 // have to identify the support for new tags by version.
1210 bool new_ed2k =
1211 // eMule client > 0.42f
1212 (pClient && pClient->IsEmuleClient() && pClient->GetVersion() >= MAKE_CLIENT_VERSION(0,42,7))
1214 // aMule >= 2.0.0rc8. Sadly, there's no way to check the rcN number, so I checked
1215 // the rc8 changelog. On rc8 OSInfo was introduced, so...
1216 (pClient && pClient->GetClientSoft() == SO_AMULE && !pClient->GetClientOSInfo().IsEmpty())
1218 // eservers use a flag for this, at least.
1219 (pServer && (pServer->GetTCPFlags() & SRV_TCPFLG_NEWTAGS));
1221 for (TagPtrList::iterator it = tags.begin(); it != tags.end(); ++it ) {
1222 CTag* pTag = *it;
1223 if (new_ed2k) {
1224 pTag->WriteNewEd2kTag(files, eStrEncode);
1225 } else {
1226 pTag->WriteTagToFile(files, eStrEncode);
1228 delete pTag;
1233 // Updates priority of file if autopriority is activated
1234 void CKnownFile::UpdateAutoUpPriority()
1236 if (IsAutoUpPriority()) {
1237 uint32 queued = GetQueuedCount();
1238 uint8 priority = PR_NORMAL;
1240 if (queued > 20) {
1241 priority = PR_LOW;
1242 } else if (queued > 1) {
1243 priority = PR_NORMAL;
1244 } else {
1245 priority = PR_HIGH;
1248 if (GetUpPriority() != priority) {
1249 SetUpPriority(priority, false);
1250 Notify_SharedFilesUpdateItem(this);
1255 void CKnownFile::SetFileCommentRating(const wxString& strNewComment, int8 iNewRating)
1257 if (m_strComment != strNewComment || m_iRating != iNewRating) {
1258 SetLastPublishTimeKadNotes(0);
1259 wxString strCfgPath = wxT("/") + m_abyFileHash.Encode() + wxT("/");
1261 wxConfigBase* cfg = wxConfigBase::Get();
1262 if (strNewComment.IsEmpty() && iNewRating == 0) {
1263 cfg->DeleteGroup(strCfgPath);
1264 } else {
1265 cfg->Write( strCfgPath + wxT("Comment"), strNewComment);
1266 cfg->Write( strCfgPath + wxT("Rate"), (int)iNewRating);
1269 m_strComment = strNewComment;
1270 m_iRating = iNewRating;
1272 SourceSet::iterator it = m_ClientUploadList.begin();
1273 for ( ; it != m_ClientUploadList.end(); ++it ) {
1274 it->SetCommentDirty();
1280 void CKnownFile::SetUpPriority(uint8 iNewUpPriority, bool m_bsave){
1281 m_iUpPriority = iNewUpPriority;
1282 if( IsPartFile() && m_bsave ) {
1283 static_cast<CPartFile*>(this)->SavePartFile();
1287 void CKnownFile::SetPublishedED2K(bool val){
1288 m_PublishedED2K = val;
1289 Notify_SharedFilesUpdateItem(this);
1292 bool CKnownFile::PublishNotes()
1294 if(m_lastPublishTimeKadNotes > (uint32)time(NULL)) {
1295 return false;
1298 if(!GetFileComment().IsEmpty()) {
1299 m_lastPublishTimeKadNotes = (uint32)time(NULL)+KADEMLIAREPUBLISHTIMEN;
1300 return true;
1303 if(GetFileRating() != 0) {
1304 m_lastPublishTimeKadNotes = (uint32)time(NULL)+KADEMLIAREPUBLISHTIMEN;
1305 return true;
1308 return false;
1311 bool CKnownFile::PublishSrc()
1313 uint32 lastBuddyIP = 0;
1315 if( theApp->IsFirewalled() ) {
1316 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1317 if( buddy ) {
1318 lastBuddyIP = theApp->clientlist->GetBuddy()->GetIP();
1319 if( lastBuddyIP != m_lastBuddyIP ) {
1320 SetLastPublishTimeKadSrc( (uint32)time(NULL)+KADEMLIAREPUBLISHTIMES, lastBuddyIP );
1321 return true;
1323 } else {
1324 return false;
1328 if(m_lastPublishTimeKadSrc > (uint32)time(NULL)) {
1329 return false;
1332 SetLastPublishTimeKadSrc((uint32)time(NULL)+KADEMLIAREPUBLISHTIMES,lastBuddyIP);
1333 return true;
1337 void CKnownFile::UpdatePartsInfo()
1339 // Cache part count
1340 uint16 partcount = GetPartCount();
1341 bool flag = (time(NULL) - m_nCompleteSourcesTime > 0);
1343 // Ensure the frequency-list is ready
1344 if ( m_AvailPartFrequency.size() != GetPartCount() ) {
1345 m_AvailPartFrequency.clear();
1346 m_AvailPartFrequency.insert(m_AvailPartFrequency.begin(), GetPartCount(), 0);
1349 if (flag) {
1350 ArrayOfUInts16 count;
1351 count.reserve(m_ClientUploadList.size());
1353 SourceSet::iterator it = m_ClientUploadList.begin();
1354 for ( ; it != m_ClientUploadList.end(); ++it ) {
1355 CUpDownClient* client = it->GetClient();
1356 if ( !client->GetUpPartStatus().empty() && client->GetUpPartCount() == partcount ) {
1357 count.push_back(client->GetUpCompleteSourcesCount());
1361 m_nCompleteSourcesCount = m_nCompleteSourcesCountLo = m_nCompleteSourcesCountHi = 0;
1363 if( partcount > 0) {
1364 m_nCompleteSourcesCount = m_AvailPartFrequency[0];
1366 for (uint16 i = 1; i < partcount; ++i) {
1367 if( m_nCompleteSourcesCount > m_AvailPartFrequency[i]) {
1368 m_nCompleteSourcesCount = m_AvailPartFrequency[i];
1371 count.push_back(m_nCompleteSourcesCount);
1373 int32 n = count.size();
1374 if (n > 0) {
1375 std::sort(count.begin(), count.end(), std::less<uint16>());
1377 // calculate range
1378 int i = n >> 1; // (n / 2)
1379 int j = (n * 3) >> 2; // (n * 3) / 4
1380 int k = (n * 7) >> 3; // (n * 7) / 8
1382 // For complete files, trust the people your uploading to more...
1384 // For low guess and normal guess count
1385 // - If we see more sources then the guessed low and
1386 // normal, use what we see.
1387 // - If we see less sources then the guessed low,
1388 // adjust network accounts for 100%, we account for
1389 // 0% with what we see and make sure we are still
1390 // above the normal.
1391 // For high guess
1392 // Adjust 100% network and 0% what we see.
1393 if (n < 20) {
1394 if ( count[i] < m_nCompleteSourcesCount ) {
1395 m_nCompleteSourcesCountLo = m_nCompleteSourcesCount;
1396 } else {
1397 m_nCompleteSourcesCountLo = count[i];
1399 m_nCompleteSourcesCount= m_nCompleteSourcesCountLo;
1400 m_nCompleteSourcesCountHi = count[j];
1401 if( m_nCompleteSourcesCountHi < m_nCompleteSourcesCount ) {
1402 m_nCompleteSourcesCountHi = m_nCompleteSourcesCount;
1404 } else {
1405 // Many sources..
1406 // For low guess
1407 // Use what we see.
1408 // For normal guess
1409 // Adjust network accounts for 100%, we account for
1410 // 0% with what we see and make sure we are still above the low.
1411 // For high guess
1412 // Adjust network accounts for 100%, we account for 0%
1413 // with what we see and make sure we are still above the normal.
1415 m_nCompleteSourcesCountLo = m_nCompleteSourcesCount;
1416 m_nCompleteSourcesCount = count[j];
1417 if( m_nCompleteSourcesCount < m_nCompleteSourcesCountLo ) {
1418 m_nCompleteSourcesCount = m_nCompleteSourcesCountLo;
1420 m_nCompleteSourcesCountHi= count[k];
1421 if( m_nCompleteSourcesCountHi < m_nCompleteSourcesCount ) {
1422 m_nCompleteSourcesCountHi = m_nCompleteSourcesCount;
1426 m_nCompleteSourcesTime = time(NULL) + (60);
1429 Notify_SharedFilesUpdateItem(this);
1433 void CKnownFile::UpdateUpPartsFrequency( CUpDownClient* client, bool increment )
1435 if ( m_AvailPartFrequency.size() != GetPartCount() ) {
1436 m_AvailPartFrequency.clear();
1437 m_AvailPartFrequency.insert(m_AvailPartFrequency.begin(), GetPartCount(), 0);
1438 if ( !increment ) {
1439 return;
1443 const BitVector& freq = client->GetUpPartStatus();
1444 unsigned int size = freq.size();
1445 if ( size != m_AvailPartFrequency.size() ) {
1446 return;
1449 if ( increment ) {
1450 for ( unsigned int i = 0; i < size; ++i ) {
1451 if ( freq.get(i) ) {
1452 m_AvailPartFrequency[i]++;
1455 } else {
1456 for ( unsigned int i = 0; i < size; ++i ) {
1457 if ( freq.get(i) ) {
1458 m_AvailPartFrequency[i]--;
1464 void CKnownFile::ClearPriority() {
1465 if ( !m_bAutoUpPriority ) return;
1466 m_iUpPriority = ( m_bAutoUpPriority ) ? PR_HIGH : PR_NORMAL;
1467 UpdateAutoUpPriority();
1470 void GuessAndRemoveExt(CPath& name)
1472 wxString ext = name.GetExt();
1474 // Remove common two-part extensions, such as "tar.gz"
1475 if (ext == wxT("gz") || ext == wxT("bz2")) {
1476 name = name.RemoveExt();
1477 if (name.GetExt() == wxT("tar")) {
1478 name = name.RemoveExt();
1480 // might be an extension if length == 3
1481 // and also remove some common non-three-character extensions
1482 } else if (ext.Length() == 3 ||
1483 ext == wxT("7z") ||
1484 ext == wxT("rm") ||
1485 ext == wxT("jpeg") ||
1486 ext == wxT("mpeg")
1488 name = name.RemoveExt();
1492 void CKnownFile::SetFileName(const CPath& filename)
1494 CAbstractFile::SetFileName(filename);
1495 wordlist.clear();
1496 // Don't publish extension. That'd kill the node indexing e.g. "avi".
1497 CPath tmpName = GetFileName();
1498 GuessAndRemoveExt(tmpName);
1499 Kademlia::CSearchManager::GetWords(tmpName.GetPrintable(), &wordlist);
1502 #endif // CLIENT_GUI
1504 //For File Comment //
1505 void CKnownFile::LoadComment() const
1507 #ifndef CLIENT_GUI
1508 wxString strCfgPath = wxT("/") + m_abyFileHash.Encode() + wxT("/");
1510 wxConfigBase* cfg = wxConfigBase::Get();
1512 m_strComment = cfg->Read( strCfgPath + wxT("Comment"), wxEmptyString);
1513 m_iRating = cfg->Read( strCfgPath + wxT("Rate"), 0l);
1514 #endif
1516 m_bCommentLoaded = true;
1520 wxString CKnownFile::GetAICHMasterHash() const
1522 #ifdef CLIENT_GUI
1523 return m_AICHMasterHash;
1524 #else
1525 if (HasProperAICHHashSet()) {
1526 return m_pAICHHashSet->GetMasterHash().GetString();
1529 return wxEmptyString;
1530 #endif
1534 bool CKnownFile::HasProperAICHHashSet() const
1536 #ifdef CLIENT_GUI
1537 return m_AICHMasterHash.Length() != 0;
1538 #else
1539 return m_pAICHHashSet->HasValidMasterHash() &&
1540 (m_pAICHHashSet->GetStatus() == AICH_HASHSETCOMPLETE ||
1541 m_pAICHHashSet->GetStatus() == AICH_VERIFIED);
1542 #endif
1545 wxString CKnownFile::GetFeedback() const
1547 return wxString(_("File name")) + wxT(": ") + GetFileName().GetPrintable() + wxT("\n")
1548 + _("File size") + wxT(": ") + CastItoXBytes(GetFileSize()) + wxT("\n")
1549 + _("Share ratio") + CFormat(wxT(": %.2f%%\n")) % (((double)statistic.GetAllTimeTransferred() / (double)GetFileSize()) * 100.0)
1550 + _("Uploaded") + wxT(": ") + CastItoXBytes(statistic.GetTransferred()) + wxT(" (") + CastItoXBytes(statistic.GetAllTimeTransferred()) + wxT(")\n")
1551 + _("Requested") + CFormat(wxT(": %u (%u)\n")) % statistic.GetRequests() % statistic.GetAllTimeRequests()
1552 + _("Accepted") + CFormat(wxT(": %u (%u)\n")) % statistic.GetAccepts() % statistic.GetAllTimeAccepts()
1553 + _("On Queue") + CFormat(wxT(": %u\n")) % GetQueuedCount()
1554 + _("Complete sources") + CFormat(wxT(": %u\n")) % m_nCompleteSourcesCount;
1557 // File_checked_for_headers