📄 searchlist.cpp
字号:
//this file is part of eMule
//Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.emule-project.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "stdafx.h"
#include "emule.h"
#include "SearchList.h"
#include "SearchParams.h"
#include "Packets.h"
#include "OtherFunctions.h"
#include "Preferences.h"
#include "UpDownClient.h"
#include "SafeFile.h"
#include "MMServer.h"
#include "SharedFileList.h"
#include "KnownFileList.h"
#include "DownloadQueue.h"
#include "PartFile.h"
#include "CxImage/xImage.h"
#include "kademlia/utils/uint128.h"
#include "emuledlg.h"
#include "SearchDlg.h"
#include "SearchListCtrl.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
bool IsValidClientIPPort(uint32 nIP, uint16 nPort)
{
return nIP != 0
&& nPort != 0
&& (ntohl(nIP) != nPort) // this filters most of the false data
&& ((nIP & 0x000000FF) != 0)
&& ((nIP & 0x0000FF00) != 0)
&& ((nIP & 0x00FF0000) != 0)
&& ((nIP & 0xFF000000) != 0);
}
void ConvertED2KTag(CTag*& pTag)
{
if (pTag->tag.specialtag == 0 && pTag->tag.tagname != NULL)
{
static const struct
{
uint8 nID;
uint8 nED2KType;
LPCSTR pszED2KName;
} _aEmuleToED2KMetaTagsMap[] =
{
// Artist, Album and Title are disabled because they should be already part of the filename
// and would therefore be redundant information sent to the servers.. and the servers count the
// amount of sent data!
{ FT_MEDIA_ARTIST, TAGTYPE_STRING, FT_ED2K_MEDIA_ARTIST },
{ FT_MEDIA_ALBUM, TAGTYPE_STRING, FT_ED2K_MEDIA_ALBUM },
{ FT_MEDIA_TITLE, TAGTYPE_STRING, FT_ED2K_MEDIA_TITLE },
{ FT_MEDIA_LENGTH, TAGTYPE_STRING, FT_ED2K_MEDIA_LENGTH },
{ FT_MEDIA_LENGTH, TAGTYPE_UINT32, FT_ED2K_MEDIA_LENGTH },
{ FT_MEDIA_BITRATE, TAGTYPE_UINT32, FT_ED2K_MEDIA_BITRATE },
{ FT_MEDIA_CODEC, TAGTYPE_STRING, FT_ED2K_MEDIA_CODEC }
};
for (int j = 0; j < ARRSIZE(_aEmuleToED2KMetaTagsMap); j++)
{
if ( CmpED2KTagName(pTag->tag.tagname, _aEmuleToED2KMetaTagsMap[j].pszED2KName) == 0
&& ( (pTag->IsStr() && _aEmuleToED2KMetaTagsMap[j].nED2KType == TAGTYPE_STRING)
|| (pTag->IsInt() && _aEmuleToED2KMetaTagsMap[j].nED2KType == TAGTYPE_UINT32)))
{
if (pTag->IsStr())
{
if (_aEmuleToED2KMetaTagsMap[j].nID == FT_MEDIA_LENGTH)
{
UINT nMediaLength = 0;
UINT hour = 0, min = 0, sec = 0;
if (sscanf(pTag->tag.stringvalue, "%u : %u : %u", &hour, &min, &sec) == 3)
nMediaLength = hour * 3600 + min * 60 + sec;
else if (sscanf(pTag->tag.stringvalue, "%u : %u", &min, &sec) == 2)
nMediaLength = min * 60 + sec;
else if (sscanf(pTag->tag.stringvalue, "%u", &sec) == 1)
nMediaLength = sec;
CTag* tag = (nMediaLength != 0) ? new CTag(_aEmuleToED2KMetaTagsMap[j].nID, nMediaLength) : NULL;
delete pTag;
pTag = tag;
}
else
{
CTag* tag = (pTag->tag.stringvalue[0] != '\0')
? new CTag(_aEmuleToED2KMetaTagsMap[j].nID, pTag->tag.stringvalue)
: NULL;
delete pTag;
pTag = tag;
}
}
else if (pTag->IsInt())
{
CTag* tag = (pTag->tag.intvalue != 0)
? new CTag(_aEmuleToED2KMetaTagsMap[j].nID, pTag->tag.intvalue)
: NULL;
delete pTag;
pTag = tag;
}
break;
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
// CSearchFile
CSearchFile::CSearchFile(const CSearchFile* copyfrom)
{
md4cpy(m_abyFileHash, copyfrom->GetFileHash());
SetFileSize(copyfrom->GetIntTagValue(FT_FILESIZE));
SetFileName(copyfrom->GetStrTagValue(FT_FILENAME), false, false);
SetFileType(copyfrom->GetFileType());
m_nClientServerIP = copyfrom->GetClientServerIP();
m_nClientID = copyfrom->GetClientID();
m_nClientPort = copyfrom->GetClientPort();
m_nClientServerPort = copyfrom->GetClientServerPort();
m_pszDirectory = copyfrom->GetDirectory()? _tcsdup(copyfrom->GetDirectory()) : NULL;
m_nSearchID = copyfrom->GetSearchID();
m_nKademlia = copyfrom->IsKademlia();
for (int i = 0; i < copyfrom->GetTags().GetCount(); i++)
taglist.Add(new CTag(*copyfrom->GetTags().GetAt(i)));
const CSimpleArray<SServer>& servers = copyfrom->GetServers();
for (i = 0; i < servers.GetSize(); i++)
AddServer(servers[i]);
m_list_bExpanded = false;
m_list_parent = const_cast<CSearchFile*>(copyfrom);
m_list_childcount = 0;
m_bPreviewPossible = false;
m_eKnown = copyfrom->m_eKnown;
}
CSearchFile::CSearchFile(CFileDataIO* in_data, uint32 nSearchID, uint32 nServerIP, uint16 nServerPort, LPCTSTR pszDirectory, bool nKademlia)
{
m_nKademlia = nKademlia;
m_nSearchID = nSearchID;
in_data->ReadHash16(m_abyFileHash);
m_nClientID = in_data->ReadUInt32();
m_nClientPort = in_data->ReadUInt16();
if ((m_nClientID || m_nClientPort) && !IsValidClientIPPort(m_nClientID, m_nClientPort)){
if (thePrefs.GetDebugServerSearchesLevel() > 1)
Debug(_T("Filtered source from search result %s:%u\n"), DbgGetClientID(m_nClientID), m_nClientPort);
m_nClientID = 0;
m_nClientPort = 0;
}
UINT tagcount = in_data->ReadUInt32();
// NSERVER2.EXE (lugdunum v16.38 patched for Win32) returns the ClientIP+Port of the client which offered that
// file, even if that client has not filled the according fields in the OP_OFFERFILES packet with its IP+Port.
//
// 16.38.p73 (lugdunum) (propenprinz)
// *) does not return ClientIP+Port if the OP_OFFERFILES packet does not also contain it.
// *) if the OP_OFFERFILES packet does contain our HighID and Port the server returns that data at least when
// returning search results via TCP.
if (thePrefs.GetDebugServerSearchesLevel() > 1)
Debug(_T("Search Result: %s Client=%u.%u.%u.%u:%u Tags=%u\n"), md4str(m_abyFileHash), (uint8)m_nClientID,(uint8)(m_nClientID>>8),(uint8)(m_nClientID>>16),(uint8)(m_nClientID>>24), m_nClientPort, tagcount);
for (UINT i = 0; i < tagcount; i++){
CTag* toadd = new CTag(in_data);
if (thePrefs.GetDebugServerSearchesLevel() > 1)
Debug(_T(" %s\n"), toadd->GetFullInfo());
ConvertED2KTag(toadd);
if (toadd)
taglist.Add(toadd);
}
// here we have two choices
// - if the server/client sent us a filetype, we could use it (though it could be wrong)
// - we always trust our filetype list and determine the filetype by the extension of the file
//
// if we received a filetype from server, we use it.
// if we did not receive a filetype, we determine it by examining the file's extension.
//
// but, in no case, we will use the receive file type when adding this search result to the download queue, to avoid
// that we are using 'wrong' file types in part files. (this has to be handled when creating the part files)
LPCSTR pszFileType = GetStrTagValueA(FT_FILETYPE);
SetFileName(GetStrTagValue(FT_FILENAME), false, pszFileType==NULL);
SetFileSize(GetIntTagValue(FT_FILESIZE));
if (pszFileType != NULL)
{
if (strcmp(pszFileType, ED2KFTSTR_PROGRAM)==0)
{
CStringA strDetailFileType = GetFileTypeByName(GetFileName());
if (!strDetailFileType.IsEmpty())
SetFileType(strDetailFileType);
else
SetFileType(pszFileType);
}
else
SetFileType(pszFileType);
}
m_nClientServerIP = nServerIP;
m_nClientServerPort = nServerPort;
if (m_nClientServerIP && m_nClientServerPort){
SServer server(m_nClientServerIP, m_nClientServerPort);
server.m_uAvail = GetIntTagValue(FT_SOURCES);
AddServer(server);
}
m_pszDirectory = pszDirectory ? _tcsdup(pszDirectory) : NULL;
m_list_bExpanded = false;
m_list_parent = NULL;
m_list_childcount = 0;
m_bPreviewPossible = false;
m_eKnown = NotDetermined;
}
CSearchFile::CSearchFile(uint32 nSearchID, const uchar* pucFileHash, uint32 uFileSize, LPCTSTR pszFileName, int iFileType, int iAvailability)
{
m_nSearchID = nSearchID;
md4cpy(m_abyFileHash, pucFileHash);
taglist.Add(new CTag(FT_FILESIZE, uFileSize));
taglist.Add(new CTag(FT_FILENAME, pszFileName));
taglist.Add(new CTag(FT_SOURCES, iAvailability));
SetFileName(pszFileName);
SetFileSize(uFileSize);
m_nKademlia = 0;
m_nClientID = 0;
m_nClientPort = 0;
m_nClientServerIP = 0;
m_nClientServerPort = 0;
m_pszDirectory = NULL;
m_list_bExpanded = false;
m_list_parent = NULL;
m_list_childcount = 0;
m_bPreviewPossible = false;
m_eKnown = NotDetermined;
}
CSearchFile::~CSearchFile()
{
for (int i = 0; i < taglist.GetSize();i++)
delete taglist[i];
if (m_pszDirectory)
free(m_pszDirectory);
for (int i = 0; i < m_listImages.GetSize(); i++)
delete m_listImages[i];
}
uint32 CSearchFile::AddSources(uint32 count)
{
for (int i = 0; i < taglist.GetSize(); i++)
{
CTag* pTag = taglist[i];
if (pTag->tag.specialtag == FT_SOURCES)
{
if (m_nKademlia)
{
if (pTag->tag.intvalue < count)
pTag->tag.intvalue = count;
}
else
pTag->tag.intvalue += count;
return pTag->tag.intvalue;
}
}
// FT_SOURCES is not yet supported by clients, we may have to create such a tag..
CTag* pTag = new CTag(FT_SOURCES, count);
taglist.Add(pTag);
return count;
}
uint32 CSearchFile::GetSourceCount() const
{
return GetIntTagValue(FT_SOURCES);
}
uint32 CSearchFile::AddCompleteSources(uint32 count)
{
for (int i = 0; i < taglist.GetSize(); i++)
{
CTag* pTag = taglist[i];
if (pTag->tag.specialtag == FT_COMPLETE_SOURCES)
{
if (m_nKademlia)
{
if (pTag->tag.intvalue < count)
pTag->tag.intvalue = count;
}
else
pTag->tag.intvalue += count;
return pTag->tag.intvalue;
}
}
// FT_COMPLETE_SOURCES is not yet supported by all servers, we may have to create such a tag..
CTag* pTag = new CTag(FT_COMPLETE_SOURCES, count);
taglist.Add(pTag);
return count;
}
uint32 CSearchFile::GetCompleteSourceCount() const
{
return GetIntTagValue(FT_COMPLETE_SOURCES);
}
///////////////////////////////////////////////////////////////////////////////
// CSearchList
CSearchList::CSearchList(){
outputwnd = 0;
m_MobilMuleSearch = false;
}
CSearchList::~CSearchList(){
Clear();
}
void CSearchList::Clear(){
for(POSITION pos = list.GetHeadPosition(); pos != NULL; )
delete list.GetNext(pos);
list.RemoveAll();
}
void CSearchList::RemoveResults(uint32 nSearchID)
{
// this will not delete the item from the window, make sure your code does it if you call this
ASSERT( outputwnd );
for (POSITION pos = list.GetHeadPosition(); pos != NULL;)
{
POSITION posLast = pos;
CSearchFile* cur_file = list.GetNext(pos);
if (cur_file->GetSearchID() == nSearchID)
{
list.RemoveAt(posLast);
delete cur_file;
}
}
}
void CSearchList::ShowResults(uint32 nSearchID)
{
ASSERT( outputwnd );
outputwnd->SetRedraw(false);
for (POSITION pos = list.GetHeadPosition(); pos != 0;)
{
const CSearchFile* cur_file = list.GetNext(pos);
if (cur_file->GetSearchID() == nSearchID && cur_file->GetListParent() == NULL)
outputwnd->AddResult(cur_file);
}
outputwnd->SetRedraw(true);
}
void CSearchList::RemoveResult(CSearchFile* todel)
{
for (POSITION pos = list.GetHeadPosition(); pos != 0;)
{
POSITION posLast = pos;
CSearchFile* cur_file = list.GetNext(pos);
if (cur_file == todel)
{
theApp.emuledlg->searchwnd->RemoveResult(todel);
list.RemoveAt(posLast);
delete todel;
return;
}
}
}
void CSearchList::NewSearch(CSearchListCtrl* in_wnd, CStringA strResultFileType, uint32 nSearchID, bool MobilMuleSearch)
{
if (in_wnd)
outputwnd = in_wnd;
m_strResultFileType = strResultFileType;
m_nCurrentSearch = nSearchID;
m_foundFilesCount.SetAt(nSearchID,0);
m_foundSourcesCount.SetAt(nSearchID,0);
m_MobilMuleSearch = MobilMuleSearch;
}
uint16 CSearchList::ProcessSearchanswer(char* in_packet, uint32 size,
CUpDownClient* Sender, bool* pbMoreResultsAvailable, LPCTSTR pszDirectory)
{
ASSERT( Sender != NULL );
// Elandal: Assumes sizeof(void*) == sizeof(uint32)
uint32 nSearchID = (uint32)Sender;
SSearchParams* pParams = new SSearchParams;
pParams->strExpression = Sender->GetUserName();
pParams->dwSearchID = nSearchID;
pParams->bClientSharedFiles = true;
if (theApp.emuledlg->searchwnd->CreateNewTab(pParams)){
m_foundFilesCount.SetAt(nSearchID,0);
m_foundSourcesCount.SetAt(nSearchID,0);
}
else{
delete pParams;
pParams = NULL;
}
CSafeMemFile packet((BYTE*)in_packet,size);
UINT results = packet.ReadUInt32();
for (UINT i = 0; i < results; i++){
CSearchFile* toadd = new CSearchFile(&packet, nSearchID, 0, 0, pszDirectory);
if (Sender){
toadd->SetClientID(Sender->GetIP());
toadd->SetClientPort(Sender->GetUserPort());
toadd->SetClientServerIP(Sender->GetServerIP());
toadd->SetClientServerPort(Sender->GetServerPort());
if (Sender->GetServerIP() && Sender->GetServerPort()){
CSearchFile::SServer server(Sender->GetServerIP(), Sender->GetServerPort());
server.m_uAvail = 1;
toadd->AddServer(server);
}
toadd->SetPreviewPossible( Sender->GetPreviewSupport() && ED2KFT_VIDEO == GetED2KFileTypeID(toadd->GetFileName()) );
}
AddToList(toadd, true);
}
if (pbMoreResultsAvailable)
*pbMoreResultsAvailable = false;
int iAddData = (int)(packet.GetLength() - packet.GetPosition());
if (iAddData == 1){
uint8 ucMore = packet.ReadUInt8();
if (ucMore == 0x00 || ucMore == 0x01){
if (pbMoreResultsAvailable)
*pbMoreResultsAvailable = (bool)ucMore;
if (thePrefs.GetDebugClientTCPLevel() > 0)
Debug(_T(" Client search answer(%s): More=%u\n"), Sender->GetUserName(), ucMore);
}
else{
if (thePrefs.GetDebugClientTCPLevel() > 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -