Suppressed the possibility for browsable only files to be searched by hash from turtle router.

This avoids that an attacker that captures a broadcast hash request can also ask for the file.

This needed to add back explicit sources in SearchDialog and private chat transfer. I dynamically search
for sources in file lists just before calling FileRequest.

When RS links anchorClick() will work properly with Qt, we can remove the search flag "EXTRA" from the
tunnel digging in p3turtle.cc, otherwise, people having this bug can't transfer files in private chat by
copy+paste of a RS link.

Also:
	- added missing mutexes in search requests into fimonitor.cc
	- suppressed some debug info in connect manager
	- added check for write fails when dumping config files



git-svn-id: http://svn.code.sf.net/p/retroshare/code/branches/v0.5.0@3026 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
csoler 2010-05-29 13:10:32 +00:00
parent 6aded9f4e7
commit 39969cd342
11 changed files with 168 additions and 99 deletions

View File

@ -58,7 +58,6 @@ FileIndexMonitor::FileIndexMonitor(CacheStrapper *cs, NotifyBase *cb_in,std::str
FileIndexMonitor::~FileIndexMonitor() FileIndexMonitor::~FileIndexMonitor()
{ {
/* Data cleanup - TODO */ /* Data cleanup - TODO */
return;
} }
int FileIndexMonitor::SearchKeywords(std::list<std::string> keywords, std::list<DirDetails> &results,uint32_t flags) int FileIndexMonitor::SearchKeywords(std::list<std::string> keywords, std::list<DirDetails> &results,uint32_t flags)
@ -66,7 +65,10 @@ int FileIndexMonitor::SearchKeywords(std::list<std::string> keywords, std::list<
results.clear(); results.clear();
std::list<FileEntry *> firesults; std::list<FileEntry *> firesults;
fi.searchTerms(keywords, firesults); {
RsStackMutex stackM(fiMutex) ;/* LOCKED DIRS */
fi.searchTerms(keywords, firesults);
}
return filterResults(firesults,results,flags) ; return filterResults(firesults,results,flags) ;
} }
@ -76,7 +78,10 @@ int FileIndexMonitor::SearchBoolExp(Expression *exp, std::list<DirDetails>& resu
results.clear(); results.clear();
std::list<FileEntry *> firesults; std::list<FileEntry *> firesults;
fi.searchBoolExp(exp, firesults); {
RsStackMutex stackM(fiMutex) ;/* LOCKED DIRS */
fi.searchBoolExp(exp, firesults);
}
return filterResults(firesults,results,flags) ; return filterResults(firesults,results,flags) ;
} }
@ -109,53 +114,64 @@ int FileIndexMonitor::filterResults(std::list<FileEntry*>& firesults,std::list<D
return !results.empty() ; return !results.empty() ;
} }
bool FileIndexMonitor::findLocalFile(std::string hash,uint32_t flags, std::string &fullpath, uint64_t &size) const bool FileIndexMonitor::findLocalFile(std::string hash,uint32_t hint_flags, std::string &fullpath, uint64_t &size) const
{ {
std::list<FileEntry *> results; std::list<FileEntry *> results;
bool ok = false; bool ok = false;
fiMutex.lock(); { /* LOCKED DIRS */
#ifdef FIM_DEBUG
std::cerr << "FileIndexMonitor::findLocalFile() Hash: " << hash << std::endl;
#endif
/* search through the fileIndex */
fi.searchHash(hash, results);
if (results.size() > 0)
{ {
/* find the full path for the first entry */ RsStackMutex stackM(fiMutex) ;/* LOCKED DIRS */
FileEntry *fe = results.front();
DirEntry *de = fe->parent; /* all files must have a valid parent! */
#ifdef FIM_DEBUG #ifdef FIM_DEBUG
std::cerr << "FileIndexMonitor::findLocalFile() Found Name: " << fe->name << std::endl; std::cerr << "FileIndexMonitor::findLocalFile() Hash: " << hash << std::endl;
#endif #endif
std::string shpath = RsDirUtil::removeRootDir(de->path); /* search through the fileIndex */
std::string basedir = RsDirUtil::getRootDir(de->path); fi.searchHash(hash, results);
std::string realroot = locked_findRealRoot(basedir);
/* construct full name */ if (results.size() > 0)
if (realroot.length() > 0)
{ {
fullpath = realroot + "/"; /* find the full path for the first entry */
if (shpath != "") FileEntry *fe = results.front();
{ DirEntry *de = fe->parent; /* all files must have a valid parent! */
fullpath += shpath + "/";
}
fullpath += fe->name;
size = fe->size; uint32_t share_flags = locked_findShareFlags(fe) ;
ok = true;
}
#ifdef FIM_DEBUG #ifdef FIM_DEBUG
std::cerr << "FileIndexMonitor::findLocalFile() Found Path: " << fullpath << std::endl; std::cerr << "FileIndexMonitor::findLocalFile: Filtering candidate " << fe->name << ", flags=" << share_flags << ", hint_flags=" << hint_flags << std::endl ;
std::cerr << "FileIndexMonitor::findLocalFile() Found Size: " << size << std::endl;
#endif #endif
}
if((share_flags & hint_flags & (RS_FILE_HINTS_BROWSABLE | RS_FILE_HINTS_NETWORK_WIDE)) > 0)
{
#ifdef FIM_DEBUG
std::cerr << "FileIndexMonitor::findLocalFile() Found Name: " << fe->name << std::endl;
#endif
std::string shpath = RsDirUtil::removeRootDir(de->path);
std::string basedir = RsDirUtil::getRootDir(de->path);
std::string realroot = locked_findRealRoot(basedir);
} fiMutex.unlock(); /* UNLOCKED DIRS */ /* construct full name */
if (realroot.length() > 0)
{
fullpath = realroot + "/";
if (shpath != "")
{
fullpath += shpath + "/";
}
fullpath += fe->name;
size = fe->size;
ok = true;
}
#ifdef FIM_DEBUG
std::cerr << "FileIndexMonitor::findLocalFile() Found Path: " << fullpath << std::endl;
std::cerr << "FileIndexMonitor::findLocalFile() Found Size: " << size << std::endl;
#endif
}
#ifdef FIM_DEBUG
else
std::cerr << "FileIndexMonitor::findLocalFile() discarded" << std::endl ;
#endif
}
} /* UNLOCKED DIRS */
return ok; return ok;
} }
@ -164,28 +180,29 @@ bool FileIndexMonitor::convertSharedFilePath(std::string path, std::string &f
{ {
bool ok = false; bool ok = false;
fiMutex.lock(); { /* LOCKED DIRS */
#ifdef FIM_DEBUG
std::cerr << "FileIndexMonitor::convertSharedFilePath() path: " << path << std::endl;
#endif
std::string shpath = RsDirUtil::removeRootDir(path);
std::string basedir = RsDirUtil::getRootDir(path);
std::string realroot = locked_findRealRoot(basedir);
/* construct full name */
if (realroot.length() > 0)
{ {
fullpath = realroot + "/"; RsStackMutex stackM(fiMutex) ;/* LOCKED DIRS */
fullpath += shpath;
#ifdef FIM_DEBUG
std::cerr << "FileIndexMonitor::convertSharedFilePath() Found Path: " << fullpath << std::endl;
#endif
ok = true;
}
} fiMutex.unlock(); /* UNLOCKED DIRS */ #ifdef FIM_DEBUG
std::cerr << "FileIndexMonitor::convertSharedFilePath() path: " << path << std::endl;
#endif
std::string shpath = RsDirUtil::removeRootDir(path);
std::string basedir = RsDirUtil::getRootDir(path);
std::string realroot = locked_findRealRoot(basedir);
/* construct full name */
if (realroot.length() > 0)
{
fullpath = realroot + "/";
fullpath += shpath;
#ifdef FIM_DEBUG
std::cerr << "FileIndexMonitor::convertSharedFilePath() Found Path: " << fullpath << std::endl;
#endif
ok = true;
}
} /* UNLOCKED DIRS */
return ok; return ok;
} }
@ -244,8 +261,6 @@ void FileIndexMonitor::setPeriod(int period)
void FileIndexMonitor::run() void FileIndexMonitor::run()
//void FileIndexMonitor::run(std::string& current_job) //void FileIndexMonitor::run(std::string& current_job)
{ {
// updateCycle(current_job);
updateCycle(); updateCycle();
while(1) while(1)
@ -258,8 +273,7 @@ void FileIndexMonitor::run()
#ifndef WINDOWS_SYS #ifndef WINDOWS_SYS
sleep(1); sleep(1);
#else #else
Sleep(1000);
Sleep(1000);
#endif #endif
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ /********************************** WINDOWS/UNIX SPECIFIC PART ******************/
@ -830,28 +844,26 @@ void FileIndexMonitor::getSharedDirectories(std::list<SharedDirInfo> &dirs)
RsStackMutex stack(fiMutex) ; /* LOCKED DIRS */ RsStackMutex stack(fiMutex) ; /* LOCKED DIRS */
/* must provide pendingDirs, as other parts depend on instanteous response */ /* must provide pendingDirs, as other parts depend on instanteous response */
if (pendingDirs) if (pendingDirs)
dirs = pendingDirList; dirs = pendingDirList;
else else
{ {
/* get actual list (not pending stuff) */ /* get actual list (not pending stuff) */
std::map<std::string, SharedDirInfo>::const_iterator it; std::map<std::string, SharedDirInfo>::const_iterator it;
for(it = directoryMap.begin(); it != directoryMap.end(); it++) for(it = directoryMap.begin(); it != directoryMap.end(); it++)
dirs.push_back(it->second) ; dirs.push_back(it->second) ;
} }
} }
/* interface */ /* interface */
void FileIndexMonitor::forceDirectoryCheck() void FileIndexMonitor::forceDirectoryCheck()
{ {
fiMutex.lock(); { /* LOCKED DIRS */ RsStackMutex stack(fiMutex) ; /* LOCKED DIRS */
if (!mInCheck) if (!mInCheck)
mForceCheck = true; mForceCheck = true;
} fiMutex.unlock(); /* UNLOCKED DIRS */
} }
@ -867,18 +879,16 @@ bool FileIndexMonitor::inDirectoryCheck()
bool FileIndexMonitor::internal_setSharedDirectories() bool FileIndexMonitor::internal_setSharedDirectories()
{ {
int i; int i;
fiMutex.lock(); /* LOCKED DIRS */ RsStackMutex stack(fiMutex) ; /* LOCKED DIRS */
if (!pendingDirs) if (!pendingDirs)
{ {
if (mForceCheck) if (mForceCheck)
{ {
mForceCheck = false; mForceCheck = false;
fiMutex.unlock(); /* UNLOCKED DIRS */
return true; return true;
} }
fiMutex.unlock(); /* UNLOCKED DIRS */
return false; return false;
} }
@ -933,7 +943,6 @@ bool FileIndexMonitor::internal_setSharedDirectories()
fi.setRootDirectories(topdirs, 0); fi.setRootDirectories(topdirs, 0);
locked_saveFileIndexes() ; locked_saveFileIndexes() ;
fiMutex.unlock(); /* UNLOCKED DIRS */
return true; return true;
} }
@ -1072,35 +1081,44 @@ int FileIndexMonitor::RequestDirDetails(void *ref, DirDetails &details, uint32_t
if(ref != NULL) if(ref != NULL)
{ {
FileEntry *file = (FileEntry *) ref; FileEntry *file = (FileEntry *) ref;
DirEntry *dir = dynamic_cast<DirEntry*>(file) ;
if(dir == NULL)
dir = dynamic_cast<DirEntry*>(file->parent) ;
if(dir != NULL && dir->parent != NULL) uint32_t share_flags = locked_findShareFlags(file) ;
while(dir->parent->parent != NULL)
dir = dir->parent ;
if(dir != NULL && dir->parent != NULL) details.flags |= (( (share_flags & RS_FILE_HINTS_BROWSABLE )>0)?DIR_FLAGS_BROWSABLE :0) ;
{ details.flags |= (( (share_flags & RS_FILE_HINTS_NETWORK_WIDE)>0)?DIR_FLAGS_NETWORK_WIDE:0) ;
#ifdef FIM_DEBUG
std::cerr << "FileIndexMonitor::RequestDirDetails: top parent name=" << dir->name << std::endl ;
#endif
std::map<std::string,SharedDirInfo>::const_iterator it = directoryMap.find(dir->name) ;
if(it == directoryMap.end())
std::cerr << "*********** ERROR *********** In " << __PRETTY_FUNCTION__ << std::endl ;
else
{
details.flags |= (( (it->second.shareflags & RS_FILE_HINTS_BROWSABLE)>0)?DIR_FLAGS_BROWSABLE:0) ;
details.flags |= (( (it->second.shareflags & RS_FILE_HINTS_NETWORK_WIDE)>0)?DIR_FLAGS_NETWORK_WIDE:0) ;
#ifdef FIM_DEBUG
std::cerr << "flags = " << details.flags << std::endl ;
#endif
}
}
} }
return true ; return true ;
} }
uint32_t FileIndexMonitor::locked_findShareFlags(FileEntry *file) const
{
uint32_t flags = 0 ;
DirEntry *dir = dynamic_cast<DirEntry*>(file) ;
if(dir == NULL)
dir = dynamic_cast<DirEntry*>(file->parent) ;
if(dir != NULL && dir->parent != NULL)
while(dir->parent->parent != NULL)
dir = dir->parent ;
if(dir != NULL && dir->parent != NULL)
{
#ifdef FIM_DEBUG
std::cerr << "FileIndexMonitor::RequestDirDetails: top parent name=" << dir->name << std::endl ;
#endif
std::map<std::string,SharedDirInfo>::const_iterator it = directoryMap.find(dir->name) ;
if(it == directoryMap.end())
std::cerr << "*********** ERROR *********** In " << __PRETTY_FUNCTION__ << std::endl ;
else
flags = it->second.shareflags & (RS_FILE_HINTS_BROWSABLE | RS_FILE_HINTS_NETWORK_WIDE) ;
#ifdef FIM_DEBUG
std::cerr << "flags = " << flags << std::endl ;
#endif
}
return flags ;
}

View File

@ -120,11 +120,16 @@ class FileIndexMonitor: public CacheSource, public RsThread
/* util fns */ /* util fns */
private: private:
/* the mutex should be locked before calling these 3. */
// saves file indexs and update the cache. // saves file indexs and update the cache.
void locked_saveFileIndexes() ; void locked_saveFileIndexes() ;
/* the mutex should be locked before calling... these. */ // Finds the share flags associated with this file entry.
uint32_t locked_findShareFlags(FileEntry *fe) const ;
std::string locked_findRealRoot(std::string base) const; std::string locked_findRealRoot(std::string base) const;
void hashFiles(const std::vector<DirContentToHash>& to_hash) ; void hashFiles(const std::vector<DirContentToHash>& to_hash) ;
bool hashFile(std::string path, FileEntry &fi); /* To Implement */ bool hashFile(std::string path, FileEntry &fi); /* To Implement */

View File

@ -63,6 +63,7 @@
* #define CONTROL_DEBUG 1 * #define CONTROL_DEBUG 1
* #define DEBUG_DWLQUEUE 1 * #define DEBUG_DWLQUEUE 1
*****/ *****/
#define CONTROL_DEBUG 1
static const uint32_t SAVE_TRANSFERS_DELAY = 61 ; // save transfer progress every 61 seconds. static const uint32_t SAVE_TRANSFERS_DELAY = 61 ; // save transfer progress every 61 seconds.
static const uint32_t INACTIVE_CHUNKS_CHECK_DELAY = 60 ; // time after which an inactive chunk is released static const uint32_t INACTIVE_CHUNKS_CHECK_DELAY = 60 ; // time after which an inactive chunk is released
@ -942,7 +943,7 @@ bool ftController::alreadyHaveFile(const std::string& hash)
return true ; return true ;
// check for file lists // check for file lists
if (mSearch->search(hash, RS_FILE_HINTS_LOCAL | RS_FILE_HINTS_EXTRA | RS_FILE_HINTS_SPEC_ONLY, info)) if (mSearch->search(hash, RS_FILE_HINTS_NETWORK_WIDE | RS_FILE_HINTS_BROWSABLE | RS_FILE_HINTS_LOCAL | RS_FILE_HINTS_EXTRA | RS_FILE_HINTS_SPEC_ONLY, info))
return true ; return true ;
return false ; return false ;

View File

@ -695,10 +695,20 @@ bool ftDataMultiplex::handleSearchRequest(const std::string& peerId, const std::
* Do Actual search * Do Actual search
* Could be Cache File, Local or Extra * Could be Cache File, Local or Extra
* (anywhere but remote really) * (anywhere but remote really)
*
* the network wide and browsable flags are needed, otherwise results get filtered.
* For tunnel creation, the check of browsable/network wide flag is already done, so
* if we get a file download packet here, the source is already allowed to download it.
*
*/ */
FileInfo info; FileInfo info;
uint32_t hintflags = (RS_FILE_HINTS_CACHE | RS_FILE_HINTS_EXTRA | RS_FILE_HINTS_LOCAL | RS_FILE_HINTS_SPEC_ONLY); uint32_t hintflags = ( RS_FILE_HINTS_NETWORK_WIDE
| RS_FILE_HINTS_BROWSABLE
| RS_FILE_HINTS_CACHE
| RS_FILE_HINTS_EXTRA
| RS_FILE_HINTS_LOCAL
| RS_FILE_HINTS_SPEC_ONLY);
if (mSearch->search(hash, hintflags, info)) if (mSearch->search(hash, hintflags, info))
{ {

View File

@ -136,8 +136,10 @@ bool ftFiMonitor::search(std::string hash, uint32_t hintflags, FileInfo &info) c
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
// setup search flags according to hintflags // Setup search flags according to hintflags. Originally flags was 0. I (cyril) don't know
uint32_t flags = 0; // why we don't just pass hintflags there, so I tried to keep the idea.
//
uint32_t flags = hintflags & (RS_FILE_HINTS_BROWSABLE | RS_FILE_HINTS_NETWORK_WIDE);
if(findLocalFile(hash, flags, path, fsize)) if(findLocalFile(hash, flags, path, fsize))
{ {

View File

@ -768,7 +768,12 @@ bool p3Config::backedUpFileSave(const std::string& cfg_fname, const std::string&
} }
if(size_file != fwrite(buff, 1, size_file, cfg_file)) if(size_file != fwrite(buff, 1, size_file, cfg_file))
{
getPqiNotify()->AddSysMessage(0, RS_SYS_WARNING, "Write error", "Error while writing backup configuration file " + cfg_fname_backup + "\nIs your disc full or out of quota ?"); getPqiNotify()->AddSysMessage(0, RS_SYS_WARNING, "Write error", "Error while writing backup configuration file " + cfg_fname_backup + "\nIs your disc full or out of quota ?");
fclose(cfg_file);
return false ;
}
fclose(cfg_file); fclose(cfg_file);

View File

@ -3543,8 +3543,10 @@ void peerConnectState::updateIpAddressList(const IpAddressTimed& ipTimed)
else else
++it,++cnt ; ++it,++cnt ;
#ifdef CONN_DEBUG
std::cerr << "Adress list updated:" << std::endl ; std::cerr << "Adress list updated:" << std::endl ;
printIpAddressList(); printIpAddressList();
#endif
} }
void peerConnectState::printIpAddressList() void peerConnectState::printIpAddressList()

View File

@ -1740,7 +1740,7 @@ void p3turtle::returnSearchResult(RsTurtleSearchResultItem *item)
// //
bool p3turtle::performLocalHashSearch(const TurtleFileHash& hash,FileInfo& info) bool p3turtle::performLocalHashSearch(const TurtleFileHash& hash,FileInfo& info)
{ {
return rsFiles->FileDetails(hash, RS_FILE_HINTS_LOCAL | RS_FILE_HINTS_EXTRA | RS_FILE_HINTS_SPEC_ONLY | RS_FILE_HINTS_DOWNLOAD, info); return rsFiles->FileDetails(hash, RS_FILE_HINTS_NETWORK_WIDE | RS_FILE_HINTS_LOCAL | RS_FILE_HINTS_EXTRA | RS_FILE_HINTS_SPEC_ONLY | RS_FILE_HINTS_DOWNLOAD, info);
} }
static std::string printNumber(uint64_t num,bool hex=false) static std::string printNumber(uint64_t num,bool hex=false)

View File

@ -263,6 +263,21 @@ void SearchDialog::searchtableWidgetCostumPopupMenu( QPoint point )
contextMnu->exec( mevent->globalPos() ); contextMnu->exec( mevent->globalPos() );
} }
void SearchDialog::getSourceFriendsForHash(const std::string& hash,std::list<std::string>& srcIds)
{
std::cerr << "Searching sources for file " << hash << std::endl ;
srcIds.clear();
FileInfo finfo ;
rsFiles->FileDetails(hash, RS_FILE_HINTS_REMOTE,finfo) ;
for(std::list<TransferInfo>::const_iterator it(finfo.peers.begin());it!=finfo.peers.end();++it)
{
std::cerr << " adding peerid " << (*it).peerId << std::endl ;
srcIds.push_back((*it).peerId) ;
}
}
void SearchDialog::download() void SearchDialog::download()
{ {
/* should also be able to handle multi-selection */ /* should also be able to handle multi-selection */
@ -281,6 +296,8 @@ void SearchDialog::download()
std::cerr << std::endl; std::cerr << std::endl;
std::list<std::string> srcIds; std::list<std::string> srcIds;
getSourceFriendsForHash((item->text(SR_HASH_COL)).toStdString(),srcIds) ;
if(!rsFiles -> FileRequest((item->text(SR_NAME_COL)).toStdString(), if(!rsFiles -> FileRequest((item->text(SR_NAME_COL)).toStdString(),
(item->text(SR_HASH_COL)).toStdString(), (item->text(SR_HASH_COL)).toStdString(),
(item->text(SR_SIZE_COL)).toULongLong(), (item->text(SR_SIZE_COL)).toULongLong(),
@ -310,6 +327,8 @@ void SearchDialog::downloadDirectory(const QTreeWidgetItem *item, const QString
+ tr("/") + base + tr("/"); + tr("/") + base + tr("/");
QString cleanPath = QDir::cleanPath(path); QString cleanPath = QDir::cleanPath(path);
getSourceFriendsForHash((item->text(SR_HASH_COL)).toStdString(),srcIds) ;
rsFiles->FileRequest(item->text(SR_NAME_COL).toStdString(), rsFiles->FileRequest(item->text(SR_NAME_COL).toStdString(),
item->text(SR_HASH_COL).toStdString(), item->text(SR_HASH_COL).toStdString(),
item->text(SR_SIZE_COL).toULongLong(), item->text(SR_SIZE_COL).toULongLong(),

View File

@ -104,6 +104,8 @@ private:
void insertDirectory(const std::string &txt, qulonglong searchId, const DirDetails &dir); void insertDirectory(const std::string &txt, qulonglong searchId, const DirDetails &dir);
void setIconAndType(QTreeWidgetItem *item, QString &ext); void setIconAndType(QTreeWidgetItem *item, QString &ext);
void downloadDirectory(const QTreeWidgetItem *item, const QString &base); void downloadDirectory(const QTreeWidgetItem *item, const QString &base);
void getSourceFriendsForHash(const std::string& hash,std::list<std::string>& srcIds);
/** the advanced search dialog instance */ /** the advanced search dialog instance */

View File

@ -851,13 +851,18 @@ void PopupChatDialog::anchorClicked (const QUrl& link )
if(!rslink.valid()) if(!rslink.valid())
{ {
QMessageBox mb(tr("Badly formed RS link"), tr("This RetroShare link is malformed. This is bug. Please contact the developers.\n\nNote: this possibly comes from a bug in Qt4.6. Try to right-click + copy link location."),QMessageBox::Information,QMessageBox::Ok,0,0); QMessageBox mb(tr("Badly formed RS link"), tr("This RetroShare link is malformed. This is bug. Please contact the developers.\n\nNote: this possibly comes from a bug in Qt4.6. Try to right-click + copy link location, and paste in Transfer Tab."),QMessageBox::Information,QMessageBox::Ok,0,0);
mb.setButtonText( QMessageBox::Ok, "OK" ); mb.setButtonText( QMessageBox::Ok, "OK" );
mb.exec(); mb.exec();
return ; return ;
} }
std::list<std::string> srcIds ;
srcIds.push_back(dialogId);
if(rsFiles->FileRequest(rslink.name().toStdString(), rslink.hash().toStdString(), rslink.size(), "", RS_FILE_HINTS_NETWORK_WIDE, std::list<std::string>())) // I removed the NETWORK WIDE flag. Indeed, somebody can capture the turtle tunnel requests and ask for downloading the file while
// it's being downloaded (as partial files are always sources).
//
if(rsFiles->FileRequest(rslink.name().toStdString(), rslink.hash().toStdString(), rslink.size(), "", 0, srcIds))
{ {
QMessageBox mb(tr("File Request Confirmation"), tr("The file has been added to your download list."),QMessageBox::Information,QMessageBox::Ok,0,0); QMessageBox mb(tr("File Request Confirmation"), tr("The file has been added to your download list."),QMessageBox::Information,QMessageBox::Ok,0,0);
mb.setButtonText( QMessageBox::Ok, "OK" ); mb.setButtonText( QMessageBox::Ok, "OK" );