📄 sharedfilelist.cpp
字号:
if (pPersistFile){
USES_CONVERSION;
if (SUCCEEDED(pPersistFile->Load(T2COLE(ff.GetFilePath()), STGM_READ))){
TCHAR szResolvedPath[MAX_PATH];
if (pShellLink->GetPath(szResolvedPath, ARRSIZE(szResolvedPath), NULL, 0) == NOERROR){
TRACE(_T("%hs: Did not share file \"%s\" - not supported file type\n"), __FUNCTION__, ff.GetFilePath());
continue;
}
}
}
}
}
}
// ignore real(!) thumbs.db files -- seems that lot of ppl have 'thumbs.db' files without the 'System' file attribute
if (ff.GetFileName().CompareNoCase(_T("thumbs.db")) == 0)
{
// if that's a valid 'Storage' file, we declare it as a "thumbs.db" file.
USES_CONVERSION;
CComPtr<IStorage> pStorage;
if (StgOpenStorage(T2CW(ff.GetFilePath()), NULL, STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &pStorage) == S_OK)
{
CComPtr<IEnumSTATSTG> pEnumSTATSTG;
if (SUCCEEDED(pStorage->EnumElements(0, NULL, 0, &pEnumSTATSTG)))
{
STATSTG statstg = {0};
if (pEnumSTATSTG->Next(1, &statstg, 0) == S_OK)
{
CoTaskMemFree(statstg.pwcsName);
statstg.pwcsName = NULL;
TRACE(_T("%hs: Did not share file \"%s\" - not supported file type\n"), __FUNCTION__, ff.GetFilePath());
continue;
}
}
}
}
CTime lwtime;
if (!ff.GetLastWriteTime(lwtime)){
if (thePrefs.GetVerbose())
AddDebugLogLine(false, _T("Failed to get file date of %s - %s"), ff.GetFilePath(), GetErrorMessage(GetLastError()));
}
uint32 fdate = lwtime.GetTime();
if (fdate == -1){
if (thePrefs.GetVerbose())
AddDebugLogLine(false, _T("Failed to convert file date of %s"), ff.GetFilePath());
}
else
AdjustNTFSDaylightFileTime(fdate, ff.GetFilePath());
CKnownFile* toadd = theApp.knownfiles->FindKnownFile(ff.GetFileName(), fdate, (uint32)ff.GetLength());
if (toadd)
{
CCKey key(toadd->GetFileHash());
CKnownFile* pFileInMap;
if (m_Files_map.Lookup(key, pFileInMap))
{
TRACE(_T("%hs: File already in shared file list: %s \"%s\"\n"), __FUNCTION__, md4str(pFileInMap->GetFileHash()), pFileInMap->GetFilePath());
TRACE(_T("%hs: File to add: %s \"%s\"\n"), __FUNCTION__, md4str(toadd->GetFileHash()), ff.GetFilePath());
if (!pFileInMap->IsKindOf(RUNTIME_CLASS(CPartFile)) || theApp.downloadqueue->IsPartFile(pFileInMap))
AddLogLine(false, _T("Duplicate shared files: \"%s\" and \"%s\""), pFileInMap->GetFilePath(), ff.GetFilePath());
}
else
{
toadd->SetPath(rstrDirectory);
toadd->SetFilePath(ff.GetFilePath());
AddFile(toadd);
}
}
else
{
//not in knownfilelist - start adding thread to hash file if the hashing of this file isnt already waiting
// SLUGFILLER: SafeHash - don't double hash, MY way
if (!IsHashing(rstrDirectory, ff.GetFileName()) && !thePrefs.IsTempFile(rstrDirectory, ff.GetFileName())){
UnknownFile_Struct* tohash = new UnknownFile_Struct;
tohash->strDirectory = rstrDirectory;
tohash->strName = ff.GetFileName();
waitingforhash_list.AddTail(tohash);
}
else
TRACE(_T("%hs: Did not share file \"%s\" - already hashing or temp. file\n"), __FUNCTION__, ff.GetFilePath());
// SLUGFILLER: SafeHash
}
}
ff.Close();
}
bool CSharedFileList::SafeAddKFile(CKnownFile* toadd, bool bOnlyAdd)
{
bool bAdded = false;
RemoveFromHashing(toadd); // SLUGFILLER: SafeHash - hashed ok, remove from list, in case it was on the list
bAdded = AddFile(toadd);
if (bOnlyAdd)
return bAdded;
if (output)
output->ShowFile(toadd);
m_lastPublishED2KFlag = true;
return bAdded;
}
void CSharedFileList::RepublishFile(CKnownFile* pFile)
{
CServer* pCurServer = server->GetCurrentServer();
if (pCurServer && (pCurServer->GetTCPFlags() & SRV_TCPFLG_COMPRESSION))
{
m_lastPublishED2KFlag = true;
pFile->SetPublishedED2K(false); // FIXME: this creates a wrong 'No' for the ed2k shared info in the listview until the file is shared again.
}
}
bool CSharedFileList::AddFile(CKnownFile* pFile)
{
ASSERT( pFile->GetHashCount() == pFile->GetED2KPartHashCount() );
ASSERT( !pFile->IsKindOf(RUNTIME_CLASS(CPartFile)) || !STATIC_DOWNCAST(CPartFile, pFile)->hashsetneeded );
CCKey key(pFile->GetFileHash());
CKnownFile* pFileInMap;
if (m_Files_map.Lookup(key, pFileInMap))
{
TRACE(_T("%hs: File already in shared file list: %s \"%s\" \"%s\"\n"), __FUNCTION__, md4str(pFileInMap->GetFileHash()), pFileInMap->GetFileName(), pFileInMap->GetFilePath());
TRACE(_T("%hs: File to add: %s \"%s\" \"%s\"\n"), __FUNCTION__, md4str(pFile->GetFileHash()), pFile->GetFileName(), pFile->GetFilePath());
if (!pFileInMap->IsKindOf(RUNTIME_CLASS(CPartFile)) || theApp.downloadqueue->IsPartFile(pFileInMap))
AddLogLine(false, _T("Duplicate shared files: \"%s\" and \"%s\""), pFileInMap->GetFilePath(), pFile->GetFilePath());
return false;
}
m_UnsharedFiles_map.RemoveKey(CSKey(pFile->GetFileHash()));
m_Files_map.SetAt(key, pFile);
m_keywords->AddKeywords(pFile);
return true;
}
void CSharedFileList::FileHashingFinished(CKnownFile* file)
{
// File hashing finished for a shared file (none partfile)
// - reading shared directories at startup and hashing files which were not found in known.met
// - reading shared directories during runtime (user hit Reload button, added a shared directory, ...)
ASSERT( !IsFilePtrInList(file) );
ASSERT( !theApp.knownfiles->IsFilePtrInList(file) );
CKnownFile* found_file = GetFileByID(file->GetFileHash());
if (found_file == NULL)
{
SafeAddKFile(file);
theApp.knownfiles->SafeAddKFile(file);
}
else
{
TRACE(_T("%hs: File already in shared file list: %s \"%s\"\n"), __FUNCTION__, md4str(found_file->GetFileHash()), found_file->GetFilePath());
TRACE(_T("%hs: File to add: %s \"%s\"\n"), __FUNCTION__, md4str(file->GetFileHash()), file->GetFilePath());
AddLogLine(false, _T("Duplicate shared files: \"%s\" and \"%s\""), found_file->GetFilePath(), file->GetFilePath());
RemoveFromHashing(file);
if (!IsFilePtrInList(file) && !theApp.knownfiles->IsFilePtrInList(file))
delete file;
else
ASSERT(0);
}
}
void CSharedFileList::RemoveFile(CKnownFile* pFile)
{
output->RemoveFile(pFile);
m_UnsharedFiles_map.SetAt(CSKey(pFile->GetFileHash()), true);
m_Files_map.RemoveKey(CCKey(pFile->GetFileHash()));
m_keywords->RemoveKeywords(pFile);
}
void CSharedFileList::Reload()
{
m_keywords->RemoveAllKeywordReferences();
FindSharedFiles();
m_keywords->PurgeUnreferencedKeywords();
if (output)
output->ShowFileList(this);
}
void CSharedFileList::SetOutputCtrl(CSharedFilesCtrl* in_ctrl)
{
output = in_ctrl;
output->ShowFileList(this);
HashNextFile(); // SLUGFILLER: SafeHash - if hashing not yet started, start it now
}
uint8 GetRealPrio(uint8 in)
{
switch(in) {
case 4 : return 0;
case 0 : return 1;
case 1 : return 2;
case 2 : return 3;
case 3 : return 4;
}
return 0;
}
void CSharedFileList::SendListToServer(){
if (m_Files_map.IsEmpty() || !server->IsConnected())
{
return;
}
CSafeMemFile files(1024);
CCKey bufKey;
CKnownFile* cur_file,cur_file2;
POSITION pos,pos2;
CTypedPtrList<CPtrList, CKnownFile*> sortedList;
bool added=false;
for(pos=m_Files_map.GetStartPosition(); pos!=0;)
{
m_Files_map.GetNextAssoc(pos, bufKey, cur_file);
added=false;
//insertsort into sortedList
if(!cur_file->GetPublishedED2K())
{
for (pos2 = sortedList.GetHeadPosition();pos2 != 0 && !added;sortedList.GetNext(pos2))
{
if (GetRealPrio(sortedList.GetAt(pos2)->GetUpPriority()) <= GetRealPrio(cur_file->GetUpPriority()) )
{
sortedList.InsertBefore(pos2,cur_file);
added=true;
}
}
if (!added)
{
sortedList.AddTail(cur_file);
}
}
}
CServer* pCurServer = server->GetCurrentServer();
// add to packet
uint32 limit = pCurServer ? pCurServer->GetSoftFiles() : 0;
if( limit == 0 || limit > 200 )
{
limit = 200;
}
if( (uint32)sortedList.GetCount() < limit )
{
limit = sortedList.GetCount();
if (limit == 0)
{
m_lastPublishED2KFlag = false;
return;
}
}
files.WriteUInt32(limit);
uint32 count=0;
for (pos = sortedList.GetHeadPosition();pos != 0 && count<limit; )
{
count++;
CKnownFile* file = sortedList.GetNext(pos);
CreateOfferedFilePacket(file, &files, pCurServer);
file->SetPublishedED2K(true);
}
sortedList.RemoveAll();
Packet* packet = new Packet(&files);
packet->opcode = OP_OFFERFILES;
// compress packet
// - this kind of data is highly compressable (N * (1 MD4 and at least 3 string meta data tags and 1 integer meta data tag))
// - the min. amount of data needed for one published file is ~100 bytes
// - this function is called once when connecting to a server and when a file becomes shareable - so, it's called rarely.
// - if the compressed size is still >= the original size, we send the uncompressed packet
// therefor we always try to compress the packet
if (pCurServer && pCurServer->GetTCPFlags() & SRV_TCPFLG_COMPRESSION){
UINT uUncomprSize = packet->size;
packet->PackPacket();
if (thePrefs.GetDebugServerTCPLevel() > 0)
Debug(_T(">>> Sending OP__OfferFiles(compressed); uncompr size=%u compr size=%u files=%u\n"), uUncomprSize, packet->size, limit);
}
else{
if (thePrefs.GetDebugServerTCPLevel() > 0)
Debug(_T(">>> Sending OP__OfferFiles; size=%u files=%u\n"), packet->size, limit);
}
theStats.AddUpDataOverheadServer(packet->size);
if (thePrefs.GetVerbose())
AddDebugLogLine(false, _T("Server, Sendlist: Packet size:%u"), packet->size);
server->SendPacket(packet,true);
}
CKnownFile* CSharedFileList::GetFileByIndex(int index){
int count=0;
CKnownFile* cur_file;
CCKey bufKey;
for (POSITION pos = m_Files_map.GetStartPosition();pos != 0;){
m_Files_map.GetNextAssoc(pos,bufKey,cur_file);
if (index==count)
return cur_file;
count++;
}
return 0;
}
void CSharedFileList::ClearED2KPublishInfo(){
CKnownFile* cur_file;
CCKey bufKey;
m_lastPublishED2KFlag = true;
for (POSITION pos = m_Files_map.GetStartPosition();pos != 0;){
m_Files_map.GetNextAssoc(pos,bufKey,cur_file);
cur_file->SetPublishedED2K(false);
}
}
void CSharedFileList::CreateOfferedFilePacket(const CKnownFile* cur_file, CSafeMemFile* files,
CServer* pServer, CUpDownClient* pClient)
{
UINT uEmuleVer = (pClient && pClient->IsEmuleClient()) ? pClient->GetVersion() : 0;
// NOTE: This function is used for creating the offered file packet for Servers _and_ for Clients..
files->WriteHash16(cur_file->GetFileHash());
// *) This function is used for offering files to the local server and for sending
// shared files to some other client. In each case we send our IP+Port only, if
// we have a HighID.
// *) Newer eservers also support 2 special IP+port values which are used to hold basic file status info.
uint32 nClientID = 0;
uint16 nClientPort = 0;
if (pServer)
{
// we use the 'TCP-compression' server feature flag as indicator for a 'newer' server.
if (pServer->GetTCPFlags() & SRV_TCPFLG_COMPRESSION)
{
if (cur_file->IsPartFile())
{
// publishing an incomplete file
nClientID = 0xFCFCFCFC;
nClientPort = 0xFCFC;
}
else
{
// publishing a complete file
nClientID = 0xFBFBFBFB;
nClientPort = 0xFBFB;
}
}
else
{
// check eD2K ID state
if (theApp.serverconnect->IsConnected() && !theApp.serverconnect->IsLowID())
{
nClientID = theApp.GetID();
nClientPort = thePrefs.GetPort();
}
}
}
else
{
if (theApp.IsConnected() && !theApp.IsFirewalled())
{
nClientID = theApp.GetID();
nClientPort = thePrefs.GetPort();
}
}
files->WriteUInt32(nClientID);
files->WriteUInt16(nClientPort);
//TRACE("Publishing file: Hash=%s ClientIP=%s ClientPort=%u\n", md4str(cur_file->GetFileHash()), ipstr(nClientID), nClientPort);
CSimpleArray<CTag*> tags;
tags.Add(new CTag(FT_FILENAME, cur_file->GetFileName()));
tags.Add(new CTag(FT_FILESIZE, cur_file->GetFileSize()));
// NOTE: Archives and CD-Images are published with file type "Pro"
CString strED2KFileType(GetED2KFileTypeSearchTerm(GetED2KFileTypeID(cur_file->GetFileName())));
if (!strED2KFileType.IsEmpty())
tags.Add(new CTag(FT_FILETYPE, strED2KFileType));
CString strExt;
int iExt = cur_file->GetFileName().ReverseFind(_T('.'));
if (iExt != -1){
strExt = cur_file->GetFileName().Mid(iExt);
if (!strExt.IsEmpty()){
strExt = strExt.Mid(1);
if (!strExt.IsEmpty()){
strExt.MakeLower();
tags.Add(new CTag(FT_FILEFORMAT, strExt)); // file extension without a "."
}
}
}
// only send verified meta data to servers/clients
if (cur_file->GetMetaDataVer() > 0)
{
static const struct
{
bool bSendToServer;
uint8 nName;
uint8 nED2KType;
LPCSTR pszED2KName;
} _aMetaTags[] =
{
// 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!
{ false, FT_MEDIA_ARTIST, TAGTYPE_STRING, FT_ED2K_MEDIA_ARTIST },
{ false, FT_MEDIA_ALBUM, TAGTYPE_STRING, FT_ED2K_MEDIA_ALBUM },
{ false, FT_MEDIA_TITLE, TAGTYPE_STRING, FT_ED2K_MEDIA_TITLE },
{ true, FT_MEDIA_LENGTH, TAGTYPE_STRING, FT_ED2K_MEDIA_LENGTH },
{ true, FT_MEDIA_BITRATE, TAGTYPE_UINT32, FT_ED2K_MEDIA_BITRATE },
{ true, FT_MEDIA_CODEC, TAGTYPE_STRING, FT_ED2K_MEDIA_CODEC }
};
for (int i = 0; i < ARRSIZE(_aMetaTags); i++)
{
if (pServer!=NULL && !_aMetaTags[i].bSendToServer)
continue;
CTag* pTag = cur_file->GetTag(_aMetaTags[i].nName);
if (pTag != NULL)
{
// skip string tags with empty string values
if (pTag->IsStr() && pTag->GetStr().IsEmpty())
continue;
// skip integer tags with '0' values
if (pTag->IsInt() && pTag->GetInt() == 0)
continue;
if (_aMetaTags[i].nED2KType == TAGTYPE_STRING && pTag->IsStr())
{
if (pServer && (pServer->GetTCPFlags() & SRV_TCPFLG_NEWTAGS))
tags.Add(new CTag(_aMetaTags[i].nName, pTag->GetStr()));
else
tags.Add(new CTag(_aMetaTags[i].pszED2KName, pTag->GetStr()));
}
else if (_aMetaTags[i].nED2KType == TAGTYPE_UINT32 && pTag->IsInt())
{
if (pServer && (pServer->GetTCPFlags() & SRV_TCPFLG_NEWTAGS))
tags.Add(new CTag(_aMetaTags[i].nName, pTag->GetInt()));
else
tags.Add(new CTag(_aMetaTags[i].pszED2KName, pTag->GetInt()));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -