/* * This file Copyright (C) 2009-2015 Mnemosyne LLC * * It may be used under the GNU GPL versions 2 or 3 * or any future license endorsed by Mnemosyne LLC. * */ #include #include #include #include #include #include "Prefs.h" #include "TorrentModel.h" #include "WatchDir.h" /*** **** ***/ WatchDir::WatchDir(const TorrentModel& model) : myModel(model), myWatcher(0) { } WatchDir::~WatchDir() { } /*** **** ***/ int WatchDir::metainfoTest(const QString& filename) const { int ret; tr_info inf; tr_ctor* ctor = tr_ctorNew(0); // parse tr_ctorSetMetainfoFromFile(ctor, filename.toUtf8().constData()); const int err = tr_torrentParse(ctor, &inf); if (err) { ret = ERROR; } else if (myModel.hasTorrent(QString::fromUtf8(inf.hashString))) { ret = DUPLICATE; } else { ret = OK; } // cleanup if (!err) { tr_metainfoFree(&inf); } tr_ctorFree(ctor); return ret; } void WatchDir::onTimeout() { QTimer* t = qobject_cast(sender()); const QString filename = t->objectName(); if (metainfoTest(filename) == OK) { emit torrentFileAdded(filename); } t->deleteLater(); } void WatchDir::setPath(const QString& path, bool isEnabled) { // clear out any remnants of the previous watcher, if any myWatchDirFiles.clear(); if (myWatcher) { delete myWatcher; myWatcher = 0; } // maybe create a new watcher if (isEnabled) { myWatcher = new QFileSystemWatcher(); myWatcher->addPath(path); connect(myWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(watcherActivated(QString))); // std::cerr << "watching " << qPrintable(path) << " for new .torrent files" << std::endl; QTimer::singleShot(0, this, SLOT(rescanAllWatchedDirectories())); // trigger the watchdir for .torrent files in there already } } void WatchDir::watcherActivated(const QString& path) { const QDir dir(path); // get the list of files currently in the watch directory QSet files; for (const QString& str : dir.entryList(QDir::Readable | QDir::Files)) { files.insert(str); } // try to add any new files which end in .torrent const QSet newFiles(files - myWatchDirFiles); const QString torrentSuffix = QString::fromUtf8(".torrent"); for (const QString& name : newFiles) { if (name.endsWith(torrentSuffix, Qt::CaseInsensitive)) { const QString filename = dir.absoluteFilePath(name); switch (metainfoTest(filename)) { case OK: emit torrentFileAdded(filename); break; case DUPLICATE: break; case ERROR: { // give the .torrent a few seconds to finish downloading QTimer* t = new QTimer(this); t->setObjectName(dir.absoluteFilePath(name)); t->setSingleShot(true); connect(t, SIGNAL(timeout()), this, SLOT(onTimeout())); t->start(5000); } } } } // update our file list so that we can use it // for comparison the next time around myWatchDirFiles = files; } void WatchDir::rescanAllWatchedDirectories() { if (myWatcher == nullptr) { return; } for (const QString& path : myWatcher->directories()) { watcherActivated(path); } }