1 | /* |
---|
2 | * This file Copyright (C) 2009-2014 Mnemosyne LLC |
---|
3 | * |
---|
4 | * It may be used under the GNU Public License v2 or v3 licenses, |
---|
5 | * or any future license endorsed by Mnemosyne LLC. |
---|
6 | * |
---|
7 | * $Id: watchdir.cc 14377 2014-12-12 23:05:10Z mikedld $ |
---|
8 | */ |
---|
9 | |
---|
10 | #include <iostream> |
---|
11 | |
---|
12 | #include <QDir> |
---|
13 | #include <QFileSystemWatcher> |
---|
14 | #include <QTimer> |
---|
15 | |
---|
16 | #include <libtransmission/transmission.h> |
---|
17 | |
---|
18 | #include "prefs.h" |
---|
19 | #include "torrent-model.h" |
---|
20 | #include "watchdir.h" |
---|
21 | |
---|
22 | /*** |
---|
23 | **** |
---|
24 | ***/ |
---|
25 | |
---|
26 | WatchDir::WatchDir (const TorrentModel& model): |
---|
27 | myModel (model), |
---|
28 | myWatcher (0) |
---|
29 | { |
---|
30 | } |
---|
31 | |
---|
32 | WatchDir::~WatchDir () |
---|
33 | { |
---|
34 | } |
---|
35 | |
---|
36 | /*** |
---|
37 | **** |
---|
38 | ***/ |
---|
39 | |
---|
40 | int |
---|
41 | WatchDir::metainfoTest (const QString& filename) const |
---|
42 | { |
---|
43 | int ret; |
---|
44 | tr_info inf; |
---|
45 | tr_ctor * ctor = tr_ctorNew (0); |
---|
46 | |
---|
47 | // parse |
---|
48 | tr_ctorSetMetainfoFromFile (ctor, filename.toUtf8().constData()); |
---|
49 | const int err = tr_torrentParse( ctor, &inf ); |
---|
50 | if (err) |
---|
51 | ret = ERROR; |
---|
52 | else if (myModel.hasTorrent (QString::fromUtf8 (inf.hashString))) |
---|
53 | ret = DUPLICATE; |
---|
54 | else |
---|
55 | ret = OK; |
---|
56 | |
---|
57 | // cleanup |
---|
58 | if (!err) |
---|
59 | tr_metainfoFree (&inf); |
---|
60 | tr_ctorFree (ctor); |
---|
61 | return ret; |
---|
62 | } |
---|
63 | |
---|
64 | void |
---|
65 | WatchDir::onTimeout () |
---|
66 | { |
---|
67 | QTimer * t = qobject_cast<QTimer*>(sender()); |
---|
68 | const QString filename = t->objectName (); |
---|
69 | |
---|
70 | if (metainfoTest (filename) == OK) |
---|
71 | emit torrentFileAdded( filename ); |
---|
72 | |
---|
73 | t->deleteLater( ); |
---|
74 | } |
---|
75 | |
---|
76 | void |
---|
77 | WatchDir::setPath (const QString& path, bool isEnabled) |
---|
78 | { |
---|
79 | // clear out any remnants of the previous watcher, if any |
---|
80 | myWatchDirFiles.clear (); |
---|
81 | if (myWatcher) |
---|
82 | { |
---|
83 | delete myWatcher; |
---|
84 | myWatcher = 0; |
---|
85 | } |
---|
86 | |
---|
87 | // maybe create a new watcher |
---|
88 | if (isEnabled) |
---|
89 | { |
---|
90 | myWatcher = new QFileSystemWatcher (); |
---|
91 | myWatcher->addPath( path ); |
---|
92 | connect (myWatcher, SIGNAL(directoryChanged(const QString&)), |
---|
93 | this, SLOT(watcherActivated(const QString&))); |
---|
94 | //std::cerr << "watching " << qPrintable(path) << " for new .torrent files" << std::endl; |
---|
95 | QTimer::singleShot (0, this, SLOT (rescanAllWatchedDirectories ())); // trigger the watchdir for .torrent files in there already |
---|
96 | } |
---|
97 | } |
---|
98 | |
---|
99 | void |
---|
100 | WatchDir::watcherActivated (const QString& path) |
---|
101 | { |
---|
102 | const QDir dir(path); |
---|
103 | |
---|
104 | // get the list of files currently in the watch directory |
---|
105 | QSet<QString> files; |
---|
106 | foreach (QString str, dir.entryList (QDir::Readable|QDir::Files)) |
---|
107 | files.insert (str); |
---|
108 | |
---|
109 | // try to add any new files which end in .torrent |
---|
110 | const QSet<QString> newFiles (files - myWatchDirFiles); |
---|
111 | const QString torrentSuffix = QString::fromUtf8 (".torrent"); |
---|
112 | foreach (QString name, newFiles) |
---|
113 | { |
---|
114 | if (name.endsWith (torrentSuffix, Qt::CaseInsensitive)) |
---|
115 | { |
---|
116 | const QString filename = dir.absoluteFilePath (name); |
---|
117 | switch (metainfoTest (filename)) |
---|
118 | { |
---|
119 | case OK: |
---|
120 | emit torrentFileAdded (filename); |
---|
121 | break; |
---|
122 | |
---|
123 | case DUPLICATE: |
---|
124 | break; |
---|
125 | |
---|
126 | case ERROR: |
---|
127 | { |
---|
128 | // give the .torrent a few seconds to finish downloading |
---|
129 | QTimer * t = new QTimer (this); |
---|
130 | t->setObjectName (dir.absoluteFilePath (name)); |
---|
131 | t->setSingleShot (true); |
---|
132 | connect( t, SIGNAL(timeout()), this, SLOT(onTimeout())); |
---|
133 | t->start (5000); |
---|
134 | } |
---|
135 | } |
---|
136 | } |
---|
137 | } |
---|
138 | |
---|
139 | // update our file list so that we can use it |
---|
140 | // for comparison the next time around |
---|
141 | myWatchDirFiles = files; |
---|
142 | } |
---|
143 | |
---|
144 | void |
---|
145 | WatchDir::rescanAllWatchedDirectories () |
---|
146 | { |
---|
147 | if (myWatcher == nullptr) |
---|
148 | return; |
---|
149 | |
---|
150 | foreach (const QString& path, myWatcher->directories ()) |
---|
151 | watcherActivated (path); |
---|
152 | } |
---|