📄 queuemanager.cpp
字号:
}
if(flags & QueueItem::FLAG_DIRECTORY_DOWNLOAD) {
DirectoryItem::List dl;
{
Lock l(cs);
DirectoryItem::DirectoryPair dp = directories.equal_range(user);
for(DirectoryItem::DirectoryIter i = dp.first; i != dp.second; ++i) {
dl.push_back(i->second);
}
directories.erase(user);
}
for(DirectoryItem::Iter i = dl.begin(); i != dl.end(); ++i) {
DirectoryItem* di = *i;
dirList.download(di->getName(), di->getTarget(), false);
delete di;
}
}
if(flags & QueueItem::FLAG_MATCH_QUEUE) {
AutoArray<char> tmp(STRING(MATCHED_FILES).size() + 16);
sprintf(tmp, CSTRING(MATCHED_FILES), matchListing(&dirList));
LogManager::getInstance()->message(user->getNick() + ": " + string(tmp));
}
}
void QueueManager::remove(const string& aTarget) throw() {
string x;
{
Lock l(cs);
QueueItem* q = fileQueue.find(aTarget);
if(q != NULL) {
if(q->isSet(QueueItem::FLAG_DIRECTORY_DOWNLOAD)) {
dcassert(q->getSources().size() == 1);
DirectoryItem::DirectoryPair dp = directories.equal_range(q->getSources()[0]->getUser());
for(DirectoryItem::DirectoryIter i = dp.first; i != dp.second; ++i) {
delete i->second;
}
directories.erase(q->getSources()[0]->getUser());
}
if(q->getStatus() == QueueItem::STATUS_RUNNING) {
x = q->getTarget();
} else if(!q->getTempTarget().empty() && q->getTempTarget() != q->getTarget()) {
File::deleteFile(q->getTempTarget() + Download::ANTI_FRAG_EXT);
File::deleteFile(q->getTempTarget());
}
userQueue.remove(q);
fire(QueueManagerListener::Removed(), q);
fileQueue.remove(q);
setDirty();
}
}
if(!x.empty()) {
DownloadManager::getInstance()->abortDownload(x);
}
}
void QueueManager::removeSource(const string& aTarget, User::Ptr& aUser, int reason, bool removeConn /* = true */) throw() {
Lock l(cs);
QueueItem* q = fileQueue.find(aTarget);
string x;
if(q != NULL) {
dcassert(q->isSource(aUser));
if(q->isSet(QueueItem::FLAG_USER_LIST)) {
remove(q->getTarget());
return;
}
if(reason == QueueItem::Source::FLAG_NO_TREE) {
QueueItem::Source* s = *q->getSource(aUser);
s->setFlag(reason);
return;
}
if(reason == QueueItem::Source::FLAG_CRC_WARN) {
// Already flagged?
QueueItem::Source* s = *q->getSource(aUser);
if(s->isSet(QueueItem::Source::FLAG_CRC_WARN)) {
reason = QueueItem::Source::FLAG_CRC_FAILED;
} else {
s->setFlag(reason);
return;
}
}
if((q->getStatus() == QueueItem::STATUS_RUNNING) && q->getCurrent()->getUser() == aUser) {
if(removeConn)
x = q->getTarget();
userQueue.setWaiting(q);
userQueue.remove(q, aUser);
} else if(q->getStatus() == QueueItem::STATUS_WAITING) {
userQueue.remove(q, aUser);
}
q->removeSource(aUser, reason);
fire(QueueManagerListener::SourcesUpdated(), q);
setDirty();
}
if(!x.empty()) {
DownloadManager::getInstance()->abortDownload(x);
}
}
void QueueManager::removeSources(User::Ptr& aUser, int reason) throw() {
string x;
{
Lock l(cs);
QueueItem* qi = NULL;
while( (qi = userQueue.getNext(aUser, QueueItem::PAUSED)) != NULL) {
if(qi->isSet(QueueItem::FLAG_USER_LIST)) {
remove(qi->getTarget());
} else {
userQueue.remove(qi, aUser);
qi->removeSource(aUser, reason);
fire(QueueManagerListener::SourcesUpdated(), qi);
setDirty();
}
}
qi = userQueue.getRunning(aUser);
if(qi != NULL) {
if(qi->isSet(QueueItem::FLAG_USER_LIST)) {
remove(qi->getTarget());
} else {
userQueue.setWaiting(qi);
userQueue.remove(qi, aUser);
x = qi->getTarget();
qi->removeSource(aUser, reason);
fire(QueueManagerListener::SourcesUpdated(), qi);
setDirty();
}
}
}
if(!x.empty()) {
DownloadManager::getInstance()->abortDownload(x);
}
}
void QueueManager::setPriority(const string& aTarget, QueueItem::Priority p) throw() {
User::List ul;
{
Lock l(cs);
QueueItem* q = fileQueue.find(aTarget);
if( (q != NULL) && (q->getPriority() != p) ) {
if( q->getStatus() != QueueItem::STATUS_RUNNING ) {
if(q->getPriority() == QueueItem::PAUSED || p == QueueItem::HIGHEST) {
// Problem, we have to request connections to all these users...
q->getOnlineUsers(ul);
}
userQueue.remove(q);
q->setPriority(p);
userQueue.add(q);
} else {
q->setPriority(p);
}
setDirty();
fire(QueueManagerListener::StatusUpdated(), q);
}
}
for(User::Iter i = ul.begin(); i != ul.end(); ++i) {
ConnectionManager::getInstance()->getDownloadConnection(*i);
}
}
void QueueManager::saveQueue() throw() {
if(!dirty)
return;
Lock l(cs);
try {
#define STRINGLEN(n) n, sizeof(n)-1
#define CHECKESCAPE(n) SimpleXML::escape(n, tmp, true)
File ff(getQueueFile() + ".tmp", File::WRITE, File::CREATE | File::TRUNCATE);
BufferedOutputStream<false> f(&ff);
f.write(SimpleXML::utf8Header);
f.write(STRINGLEN("<Downloads Version=\"" VERSIONSTRING "\">\r\n"));
string tmp;
string b32tmp;
for(QueueItem::StringIter i = fileQueue.getQueue().begin(); i != fileQueue.getQueue().end(); ++i) {
QueueItem* qi = i->second;
if(!qi->isSet(QueueItem::FLAG_USER_LIST)) {
f.write(STRINGLEN("\t<Download Target=\""));
f.write(CHECKESCAPE(qi->getTarget()));
f.write(STRINGLEN("\" Size=\""));
f.write(Util::toString(qi->getSize()));
f.write(STRINGLEN("\" Priority=\""));
f.write(Util::toString((int)qi->getPriority()));
f.write(STRINGLEN("\" Added=\""));
f.write(Util::toString(qi->getAdded()));
if(qi->getTTH() != NULL) {
b32tmp.clear();
f.write(STRINGLEN("\" TTH=\""));
f.write(qi->getTTH()->toBase32(b32tmp));
}
if(qi->getDownloadedBytes() > 0) {
f.write(STRINGLEN("\" TempTarget=\""));
f.write(CHECKESCAPE(qi->getTempTarget()));
f.write(STRINGLEN("\" Downloaded=\""));
f.write(Util::toString(qi->getDownloadedBytes()));
}
f.write(STRINGLEN("\">\r\n"));
for(QueueItem::Source::List::const_iterator j = qi->sources.begin(); j != qi->sources.end(); ++j) {
QueueItem::Source* s = *j;
f.write(STRINGLEN("\t\t<Source Nick=\""));
f.write(CHECKESCAPE(s->getUser()->getNick()));
f.write(STRINGLEN("\" Path=\""));
f.write(CHECKESCAPE(s->getPath()));
f.write(STRINGLEN("\" Utf8=\""));
f.write(s->isSet(QueueItem::Source::FLAG_UTF8) ? "1" : "0", 1);
f.write(STRINGLEN("\"/>\r\n"));
}
f.write(STRINGLEN("\t</Download>\r\n"));
}
}
for(DirectoryItem::DirectoryIter j = directories.begin(); j != directories.end(); ++j) {
DirectoryItem::Ptr d = j->second;
f.write(STRINGLEN("\t<Directory Target=\""));
f.write(CHECKESCAPE(d->getTarget()));
f.write(STRINGLEN("\" Nick=\""));
f.write(CHECKESCAPE(d->getUser()->getNick()));
f.write(STRINGLEN("\" Priority=\""));
f.write(Util::toString((int)d->getPriority()));
f.write(STRINGLEN("\" Source=\""));
f.write(CHECKESCAPE(d->getName()));
f.write(STRINGLEN("\"/>\r\n"));
}
f.write("</Downloads>\r\n");
f.flush();
ff.close();
File::deleteFile(getQueueFile());
File::renameFile(getQueueFile() + ".tmp", getQueueFile());
dirty = false;
} catch(const FileException&) {
// ...
}
// Put this here to avoid very many saves tries when disk is full...
lastSave = GET_TICK();
}
class QueueLoader : public SimpleXMLReader::CallBack {
public:
QueueLoader() : cur(NULL), inDownloads(false) { };
virtual ~QueueLoader() { }
virtual void startTag(const string& name, StringPairList& attribs, bool simple);
virtual void endTag(const string& name, const string& data);
private:
string target;
QueueItem* cur;
bool inDownloads;
};
void QueueManager::loadQueue() throw() {
try {
QueueLoader l;
SimpleXMLReader(&l).fromXML(File(getQueueFile(), File::READ, File::OPEN).read());
dirty = false;
} catch(const Exception&) {
// ...
}
}
static const string sDownload = "Download";
static const string sTempTarget = "TempTarget";
static const string sTarget = "Target";
static const string sSize = "Size";
static const string sDownloaded = "Downloaded";
static const string sPriority = "Priority";
static const string sSource = "Source";
static const string sNick = "Nick";
static const string sPath = "Path";
static const string sDirectory = "Directory";
static const string sAdded = "Added";
static const string sUtf8 = "Utf8";
static const string sTTH = "TTH";
void QueueLoader::startTag(const string& name, StringPairList& attribs, bool simple) {
QueueManager* qm = QueueManager::getInstance();
if(!inDownloads && name == "Downloads") {
inDownloads = true;
} else if(inDownloads) {
if(cur == NULL && name == sDownload) {
int flags = QueueItem::FLAG_RESUME;
int64_t size = Util::toInt64(getAttrib(attribs, sSize, 1));
if(size == 0)
return;
try {
const string& tgt = getAttrib(attribs, sTarget, 0);
target = QueueManager::checkTarget(tgt, size, flags);
if(target.empty())
return;
} catch(const Exception&) {
return;
}
QueueItem::Priority p = (QueueItem::Priority)Util::toInt(getAttrib(attribs, sPriority, 3));
u_int32_t added = (u_int32_t)Util::toInt(getAttrib(attribs, sAdded, 4));
const string& tthRoot = getAttrib(attribs, sTTH, 5);
string tempTarget = getAttrib(attribs, sTempTarget, 5);
int64_t downloaded = Util::toInt64(getAttrib(attribs, sDownloaded, 5));
if (downloaded > size || downloaded < 0)
downloaded = 0;
if(added == 0)
added = GET_TIME();
QueueItem* qi = qm->fileQueue.find(target);
if(qi == NULL) {
if(tthRoot.empty()) {
qi = qm->fileQueue.add(target, size, flags, p, tempTarget, downloaded, added, NULL);
} else {
TTHValue root(tthRoot);
qi = qm->fileQueue.add(target, size, flags, p, tempTarget, downloaded, added, &root);
}
qm->fire(QueueManagerListener::Added(), qi);
}
if(!simple)
cur = qi;
} else if(cur != NULL && name == sSource) {
const string& nick = getAttrib(attribs, sNick, 0);
if(nick.empty())
return;
const string& path = getAttrib(attribs, sPath, 1);
if(path.empty())
return;
const string& utf8 = getAttrib(attribs, sUtf8, 2);
bool isUtf8 = (utf8 == "1");
User::Ptr user = ClientManager::getInstance()->getUser(nick);
try {
if(qm->addSource(cur, path, user, 0, isUtf8) && user->isOnline())
ConnectionManager::getInstance()->getDownloadConnection(user);
} catch(const Exception&) {
return;
}
} else if(cur == NULL && name == sDirectory) {
const string& targetd = getAttrib(attribs, sTarget, 0);
if(targetd.empty())
return;
const string& nick = getAttrib(attribs, sNick, 1);
if(nick.empty())
return;
QueueItem::Priority p = (QueueItem::Priority)Util::toInt(getAttrib(attribs, sPriority, 2));
const string& source = getAttrib(attribs, sSource, 3);
if(source.empty())
return;
qm->addDirectory(source, ClientManager::getInstance()->getUser(nick), targetd, p);
}
}
}
void QueueLoader::endTag(const string& name, const string&) {
if(inDownloads) {
if(name == sDownload)
cur = NULL;
else if(name == "Downloads")
inDownloads = false;
}
}
// SearchManagerListener
void QueueManager::on(SearchManagerListener::SR, SearchResult* sr) throw() {
bool added = false;
bool wantConnection = false;
if(BOOLSETTING(AUTO_SEARCH) && sr->getTTH() != NULL) {
Lock l(cs);
QueueItem::List matches;
fileQueue.find(matches, *sr->getTTH());
for(QueueItem::Iter i = matches.begin(); i != matches.end(); ++i) {
QueueItem* qi = *i;
dcassert(qi->getTTH());
// Size compare to avoid popular spoof
bool found = (*qi->getTTH() == *sr->getTTH()) && (qi->getSize() == sr->getSize());
if(found) {
try {
wantConnection = addSource(qi, sr->getFile(), sr->getUser(), 0, false);
added = true;
} catch(const Exception&) {
// ...
}
break;
}
}
}
if(added && BOOLSETTING(AUTO_SEARCH_AUTO_MATCH)) {
try {
addList(sr->getUser(), QueueItem::FLAG_MATCH_QUEUE);
} catch(const Exception&) {
// ...
}
}
if(added && sr->getUser()->isOnline() && wantConnection)
ConnectionManager::getInstance()->getDownloadConnection(sr->getUser());
}
// ClientManagerListener
void QueueManager::on(ClientManagerListener::UserUpdated, const User::Ptr& aUser) throw() {
bool hasDown = false;
{
Lock l(cs);
for(int i = 0; i < QueueItem::LAST; ++i) {
QueueItem::UserListIter j = userQueue.getList(i).find(aUser);
if(j != userQueue.getList(i).end()) {
for(QueueItem::Iter m = j->second.begin(); m != j->second.end(); ++m)
fire(QueueManagerListener::StatusUpdated(), *m);
if(i != QueueItem::PAUSED)
hasDown = true;
}
}
if(pfsQueue.find(aUser->getCID()) != pfsQueue.end()) {
hasDown = true;
}
}
if(aUser->isOnline() && hasDown)
ConnectionManager::getInstance()->getDownloadConnection(aUser);
}
void QueueManager::on(TimerManagerListener::Second, u_int32_t aTick) throw() {
if(dirty && ((lastSave + 10000) < aTick)) {
saveQueue();
}
}
/**
* @file
* $Id: QueueManager.cpp,v 1.126 2005/03/19 13:00:45 arnetheduck Exp $
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -