Compare commits

..

244 Commits

Author SHA1 Message Date
sledgehammer999
cb5174bfa2 Bump to 3.3.11 2017-03-04 01:17:44 +02:00
sledgehammer999
9138156968 Update Changelog. 2017-03-04 01:17:43 +02:00
sledgehammer999
8a0b1fe0be Install qbittorrent-tray.png files. Fixes commit 8b805f4518. 2017-03-04 01:17:42 +02:00
sledgehammer999
3bbe304856 Bump API_VERSION to 12. 2017-03-04 01:17:41 +02:00
Chocobo1
0356172a1d Utilize escapeHtml 2017-03-04 01:17:40 +02:00
Chocobo1
80f3b19356 Add Utils::String::toHtmlEscaped 2017-03-04 01:17:39 +02:00
Chocobo1
39a569b438 Cleanup 2017-03-04 01:17:38 +02:00
Chocobo1
edaa7e85a7 [WebUI]: add X-XSS-Protection, X-Content-Type-Options, CSP header 2017-03-04 01:17:37 +02:00
ngosang
f9f7a8cbf2 [WebUI] Avoid clickjacking attacks 2017-03-04 01:17:35 +02:00
Chocobo1
7aef9828c9 [WebUI]: exclude insecure ciphers 2017-03-04 01:17:34 +02:00
Chocobo1
18ad972936 Code formatting
Remove extra private keyword
2017-03-04 01:17:33 +02:00
sledgehammer999
8b5c275934 Update copyright year. 2017-03-04 01:17:32 +02:00
sledgehammer999
59765954b8 Sync translations from Transifex and run lupdate. 2017-03-04 01:17:30 +02:00
ngosang
f5fff855bb [Search engine] Update Extratorrent plugin 2017-03-04 01:17:27 +02:00
sledgehammer999
26c713851e Use new create_torrent constructor were available. 2017-03-04 01:17:26 +02:00
Eugene Shalygin
f9b64c4e73 Disable proxy in WebUI HTTP server. Closes #6349.
Due to a bug in Qt 5.8 (QTBUG-58706) QTcpServer tries to use HTTP proxy
when it is set as default app proxy (for instance via "http_proxy"
environment variable) and this breaks the server. So we disable any proxy
in it.
2017-03-04 01:17:25 +02:00
thalieht
edf6c30cd8 Seperate seeds from peers for DHT, PeX and LSD 2017-03-04 01:17:17 +02:00
Chocobo1
83860afa60 Turn off port forwarding of WebUI by default for GUI users 2017-03-03 02:34:03 +02:00
murlakatamenka
4b7362aa6b Update mainwindow.h (remove duplicate declaration) 2017-03-03 02:34:02 +02:00
falco
dd0537d8d2 fix queue overload for add torrent at session start 2017-03-03 02:34:00 +02:00
Chocobo1
3c50cc1d2c Fix coverity issues
torrentcontentmodel: Use a variable to store filesCount
optionsdlg: add fallthrough comment to suppress warning
speedPlotview: initialize member
misc: fix wrong type used, add spaces
2017-03-03 02:33:59 +02:00
Chocobo1
78fdb68457 Use QString::toStdString()
Qt5 utilized the desired toUtf8() instead of toAscii().
2017-03-03 02:33:50 +02:00
Tim Delaney
bb1bd34ec0 Fix regex RSS matching. Closes #6337.
--HG--
branch : magao-dev
2017-03-03 02:33:49 +02:00
Tim Delaney
1841834c89 Bugfix RSS feed list and rules editor. Closes #3782, #6281.
--HG--
branch : magao-dev
2017-03-03 02:33:46 +02:00
sledgehammer999
30b70a99f1 Regenerate configure. 2017-03-03 02:32:57 +02:00
sledgehammer999
f0f2e93e4d Use @naikel's suggestions for previous commit. 2017-03-03 02:32:56 +02:00
Zach Bacon
5852c5e318 tests if qmake is in path properly 2017-03-03 02:32:55 +02:00
Zach Bacon
b38827bb8e fixes qmake pathing and also fixes a type in configure.ac 2017-03-03 02:32:54 +02:00
thalieht
240046f720 TransferListWidget: Some coding style 2017-03-03 02:32:52 +02:00
thalieht
78b1194da1 enable RSS, Search and Execution Log widgets before switching to them via hotkeys 2017-03-03 02:32:39 +02:00
thalieht
c1a66dad51 change all existing shortcuts to use Qt::Keys 2017-03-03 02:32:38 +02:00
thalieht
4a10d246c2 add hotkeys for Trackerlist Peerlist etc. 2017-03-03 02:32:37 +02:00
thalieht
125ab378a4 add hotkey for execution log tab 2017-03-03 02:32:36 +02:00
thalieht
4cd8a36b40 Transferlist: add hotkeys for double click and recheck selected torrents 2017-03-03 02:32:35 +02:00
thalieht
364df2e18c change torrentDoubleClicked() so it can be used in a hotkey 2017-03-03 02:32:33 +02:00
Eugene Shalygin
f8f2476aa5 cmake: read version numbers from the version.pri file. Closes #6350. 2017-03-03 02:32:32 +02:00
sledgehammer999
d685c9739b Remove unnecessary semicolon. 2017-03-03 02:32:31 +02:00
sledgehammer999
6fdfcf38f1 Use same casting method and fix code style. 2017-03-03 02:32:30 +02:00
sledgehammer999
7c85866881 Fix previous commit. 2017-03-03 02:32:29 +02:00
Vladimir Sinenko
37673cd86f Fixed sort order for datetime columns with empty values (closes #2988)
A small fix belonging to #2531.
During the sorting empty QDateTime values are shuffled around due to
unstable sort in QSortFilterProxyModel (see #2526 and #2158), causing
the transfer list items to constantly change order.

Fixed by using an already existing correct comparison (with a torrent
hash fallback).
2017-03-03 02:30:18 +02:00
Tim Delaney
a4a38d633c Improve UI responsiveness during RSS downloading. Closes #873, #1089, #1235, #5423.
--HG--
branch : magao-dev
2017-03-03 02:17:34 +02:00
sledgehammer999
93bdc81e3c Fix unused variable warning by gcc. 2017-03-03 02:17:33 +02:00
Vladimir Golovnev (Glassez)
827d5a22fb Save/load category filter widget state 2017-03-03 02:17:32 +02:00
dzmat
34e56eade8 reduce methods accessibility from public to private 2017-03-03 02:17:31 +02:00
Chocobo1
4a23e7da37 Use case-insensitive comparsion for torrent content window.
Closes #6327
2017-03-03 02:17:29 +02:00
sledgehammer999
f577a26fe2 Immediately update torrent_status after manipulating super seeding mode. Partially fixes #6072. 2017-03-03 02:14:35 +02:00
Tim Delaney
3f176d8265 Fix compilation error on Qt<5.4. Closes #6170.
--HG--
branch : magao-dev
2017-03-03 02:14:34 +02:00
Tim Delaney
cbc001e059 RSS allow infinite range to extend beyond current season. Closes #800, #3876, #6170.
--HG--
branch : magao-dev
2017-03-03 02:14:33 +02:00
Tim Delaney
a66ed05ecd RSS parse torrent episodes like 1x01 as well as S01E01. Closes #2749.
--HG--
branch : magao-dev
2017-03-03 02:14:32 +02:00
Tim Delaney
ec347d8dbe Allow episode zero (special) and leading zeroes in RSS episode filter.
--HG--
branch : magao-dev
2017-03-03 02:14:31 +02:00
Tim Delaney
f0acafb853 RSS use red text to indicate invalid filter. Closes #6165.
--HG--
branch : magao-dev
2017-03-03 02:14:30 +02:00
Tim Delaney
1a12e891ec Allow | in RSS must contain. Closes #6171.
--HG--
branch : magao-dev
2017-03-03 02:14:28 +02:00
Tim Delaney
88ba8e2ceb Save rule on enable/disable even if not selected. Closes #6163.
--HG--
branch : magao-dev
2017-03-03 02:14:27 +02:00
Tim Delaney
2e403277f3 RSS: allow resetting rule to no category. Closes #5539.
--HG--
branch : magao-dev
2017-03-03 02:14:26 +02:00
Tim Delaney
89349f60b0 RSS episode filter refactoring and logging (prep for later commits).
--HG--
branch : magao-dev
2017-03-03 02:14:25 +02:00
Chocobo1
0604d3729a Use case-insensitive sort for Name column in Search tab. Closes #407. 2017-03-03 02:14:09 +02:00
ngosang
cf16e3b8a1 [Web UI] Fix category in torrent upload. Closes #6260 2017-03-03 02:14:08 +02:00
Eugene Shalygin
dcb3496651 cmake: RSS target has to depend on qbt_base as it uses its includes 2017-03-03 02:14:07 +02:00
Eugene Shalygin
9d10da3ed2 cmake: fix boost components manipulations in FindLibtorrentRasterbar.cmake
The list of components which we pass to find_package() has to be semicolon
separated (i.e. to be the usual cmake list)
2017-03-03 02:14:06 +02:00
Eugene Shalygin
0524deb496 cmake: make some compile definitions global in Windows 2017-03-03 02:14:05 +02:00
Tim Delaney
787ae43d54 Move old RSS items to separate config file. Closes #6167.
--HG--
branch : magao-dev
2017-03-03 02:14:04 +02:00
Falco
67bb2cc150 fix index overflow for torrents with invalid meta data or empty progress 2017-03-03 02:14:02 +02:00
Tim Delaney
51995c80d1 Ctrl+F search filter. Closes #5797.
--HG--
branch : magao-dev
2017-03-03 02:14:01 +02:00
Tim Delaney
5f43741b09 Follow project coding style. Issue #2192.
--HG--
branch : magao-dev
2017-03-03 02:14:00 +02:00
ngosang
3328d8efd2 [Search engine] Update extratorrent plugin. Closes #6261 2017-03-03 02:13:59 +02:00
Eugene Shalygin
a54a9e5487 cmake: make LibtorrentRasterbar::LibTorrent public dependency of qbt_base
If libtorrent include directory not in the compiler search path, we have
to pass it to all qbt targets, because session.h includes
libtorrent/version.hpp
2017-03-03 02:13:58 +02:00
Eugene Shalygin
0181ca70f4 cmake: get and use only actual boost dependencies of libtorrent
With pkg-config we can get a list of Boost components from Libtorrent
dependencies and make qBittorrent depend only on these libraries in
turn. For Windows user may provide a custom list via
LibtorrentRasterbar_CUSTOM_BOOST_DEPENDENCIES variable or use generic
list which consists of date_time, system, chrono, random, thread. As a
note: in case of using fully C++11 build, the actual list contains only
boost system library.
2017-03-03 02:13:57 +02:00
buinsky
ff665af3f7 Avoid lags in firefox on resizing progress column 2017-03-03 02:13:35 +02:00
buinsky
9275cdc5bf Remove 300px limit of column width 2017-03-03 02:13:34 +02:00
buinsky
b7c3bdd443 Fix scrollbar covers menu item with long text 2017-03-03 02:13:33 +02:00
buinsky
5fd08f8664 Implement resizable progress bar in "Done" column 2017-03-03 02:13:32 +02:00
buinsky
84a4d323c7 Follow project coding style. Issue #2192. 2017-03-03 02:13:31 +02:00
buinsky
8efb13bfaf Add a vertical separator between columns 2017-03-03 02:13:29 +02:00
buinsky
0187b55610 Prevent text wrapping in menus 2017-03-03 02:13:07 +02:00
buinsky
2f606b2728 Make too tall menus scrollable 2017-03-03 02:13:06 +02:00
buinsky
025f75beca Add some missing columns to dynamic tables 2017-03-03 02:13:05 +02:00
buinsky
4711cafd20 Fix columns names 2017-03-03 02:13:04 +02:00
buinsky
8d12ca9477 Implement dynamic table columns hiding 2017-03-03 02:13:03 +02:00
buinsky
67b90bfb51 Implement dynamic table columns reordering 2017-03-03 02:12:49 +02:00
buinsky
ab05c0c326 Implement dynamic table columns resizing 2017-03-03 02:12:47 +02:00
buinsky
c5ea453438 Add tooltips to dynamic table header 2017-03-03 02:12:46 +02:00
buinsky
4f041c16e1 Make torrent peers table scrollable horizontally 2017-03-03 02:12:45 +02:00
buinsky
28cfee7bd3 Simplify dynamic table CSS styles 2017-03-03 02:12:41 +02:00
buinsky
6272287fbb Make torrents table scrollable horizontally 2017-03-03 02:12:04 +02:00
buinsky
e7a1542902 Rename variables in DynamicTable class 2017-03-03 02:12:03 +02:00
ngosang
5e371d8195 Display more information in tracker tab 2017-03-03 02:11:43 +02:00
thalieht
6bb189ea13 friendlyUnit: Properly replace spaces with non-breaking spaces 2017-03-03 02:11:42 +02:00
thalieht
8496f31e39 Increased number of digits after the decimal point for Gibibytes and above 2017-03-03 02:11:41 +02:00
sledgehammer999
08f634f748 Polish previous commit. 2017-03-03 02:11:40 +02:00
thalieht
2b5dc5c4a6 SearchTab: can now save sorting column changes 2017-03-03 02:11:39 +02:00
thalieht
0a2f0aefb3 PeerListDelegate: fix coding style in whole file 2017-03-03 02:11:38 +02:00
thalieht
66e137b8ee PeerList: allow to hide zero values for the "uploaded" and "downloaded" columns 2017-03-03 02:11:36 +02:00
thalieht
f9be39545b TransferListWidget: keep columns width even if they are hidden on qBittorrent startup (unless something goes wrong) 2017-03-03 02:11:35 +02:00
thalieht
789b8046a2 SearchTab: Allow to toggle columns in searchtab 2017-03-03 02:11:34 +02:00
thalieht
129bf497c8 SearchTab: use saveSettings() and loadSettings() to handle header state 2017-03-03 02:11:33 +02:00
thalieht
a6d7693d62 SearchTab: align text to the right in columns that handle numbers 2017-03-03 02:11:32 +02:00
thalieht
4e9fbc4da5 PeerList: align text to the right in columns that handle numbers 2017-03-03 02:11:31 +02:00
Eugene Shalygin
23f6ff4673 Fix cmake compilation 2017-03-03 02:11:30 +02:00
Vladimir Golovnev (Glassez)
3c0dfa6444 Implement category filter widget
Show categories in tree mode when subcategories are enabled.
2017-03-03 02:11:29 +02:00
Tim Delaney
694311b2bd Follow project coding style. Issue #2192.
--HG--
branch : magao-dev
2017-03-03 02:11:28 +02:00
Chocobo1
b77626897f Set default locale 2017-03-03 02:11:27 +02:00
Chocobo1
b8081feac1 Refactor
Move default value to preference class
Rename variable
Reorder headers
Remove extra parentheses
2017-03-03 02:11:25 +02:00
Bilal Elmoussaoui
8b805f4518 fixes default indicator name
copy icons instead of renaming them, create status folder

rename from *-indicator to *-tray
2017-03-03 02:11:24 +02:00
Chocobo1
8bb4f021f1 Remove trailing spaces 2017-03-03 02:11:23 +02:00
Chocobo1
97c79050dc Reset values to default, these are controled elsewhere. 2017-03-03 02:11:22 +02:00
Chocobo1
ac62a708de Speedlimitdlg: raise slider default value to 10000. Closes #6150.
Old value 1000 (KB/s) can be a bit small for modern internet.
2017-03-03 02:08:04 +02:00
Chocobo1
8d9789f51b Code rewrite, no behavior change 2017-03-03 02:08:03 +02:00
Hiro Asari
559d0228fd Allow some Mac jobs to fail
Put `allow_failures` in the correct place.
2017-03-03 02:08:02 +02:00
sledgehammer999
1296e7b891 Fix finding 'English' item in language dropdown menu when an unrecognized locale is requested. Closes #6109. 2017-03-03 02:08:01 +02:00
Chocobo1
0333e23710 After files relocate, don't remove the old folder even if it is empty. 2017-03-03 02:08:00 +02:00
Chocobo1
7320a80caa Refactor 2017-03-03 02:07:59 +02:00
Oke Atime
0579bfc069 Build qbittorrent-nox for macOS 2017-03-03 02:07:57 +02:00
Chocobo1
d20d04299e Use the numbers from tracker scrape response. Closes #5048, #6117.
Add comments
Thanks to Ian Kent for helping investigate
2017-03-03 02:07:56 +02:00
Chocobo1
50b2009e9c Fix webUI used the wrong value. Closes #6232. 2017-03-03 02:07:55 +02:00
dzmat
721d29edda DRY violation fixed 2017-03-03 02:07:54 +02:00
Chocobo1
bc9cae199b Put temp files in .qBittorrent directory. Closes #4462. 2017-03-03 02:07:53 +02:00
Chocobo1
c38b250667 Remove unused header 2017-03-03 02:07:52 +02:00
sledgehammer999
101b2f3ad2 Remove settings to exchange trackers. It wasn't used by non-libtorrent clients. Also it has a privacy risk and you might be DDoSing someone. DHT makes it obsolete anyway. 2017-03-03 02:07:51 +02:00
Eugene Shalygin
9c4f798d93 Print warning to the user if stacktrace contains no function names
Count matched function names, and if there are no, point out to the user
that the stacktrace is useless. If not all stactrace elements contain
function names, suggest user that installing debug packages may improve
the stacktrace usefulness.
2017-03-03 02:07:50 +02:00
Eugene Shalygin
249ff21738 Follow project coding style. Issue #2192. 2017-03-03 02:07:49 +02:00
dzmat
f1149097b6 Clarify options tab page objects names 2017-03-03 02:07:48 +02:00
Chocobo1
111b0df307 Fix warning: unused parameter ‘action’ [-Wunused-parameter] 2017-03-03 02:07:47 +02:00
Eugene Shalygin
8041af72cd Fetch torrent status when generating final fastresume data
This is done to get correct queue position, which has to be written into
the fastresume file. See discussion in #6154.
2017-03-03 02:07:46 +02:00
Eugene Shalygin
4be6d0b30f Add queue repair code
This is a bit adjusted code created by nxd4, who shared it in issue
disappearing).
2017-03-03 02:07:45 +02:00
Tim Delaney
8c757969f2 Fix tab order in RSS downloader. Closes #6164.
--HG--
branch : magao-dev
2017-03-03 02:07:43 +02:00
Oke Atime
ae6a82f814 Avoid unnecessary translation. Closes #6158 2017-03-03 02:07:42 +02:00
Oke Atime
eed3f0559a Webui proxy_type bug fix 2017-03-03 02:07:41 +02:00
Eugene Shalygin
c7884e7621 Do not resize SVG icons
An icon which is loaded from SVG file can be rendered in any size and
resolutions natively. We were generating 16x16, 24x24, and 32x32
pixmaps, and not appending but creating new icon. Therefore for SVG
icons we effectively were reducing their quality.

If icon already contains 7 (or more) sizes (16 to 256 px) we do not
resize it anymore.
2017-03-03 02:07:40 +02:00
Eugene Shalygin
2946ab7e7a Support fallback when selecting theme icons
Fallback icon theme are not supported everywhere. Hence we mimic
signature of QIcon::fromTheme().
2017-03-03 02:07:39 +02:00
Chocobo1
ddb8e4d21a For each cell setting ignore wheel events. Closes #866. 2017-03-03 01:46:57 +02:00
Eugene Shalygin
00d4f6141f Do not remove added files unconditionally. Closes #6248
If removing of added torrents is enabled and dialog for adding torrents
is disabled, file guard was assuming that torrent is added successfully.
And that can be not the case if a user trying to add a broken torrent
file (or not a torrent file at all). Then this file gets deleted always.

Fix this by checking result of addTorrent_impl().
2017-03-03 01:46:56 +02:00
sledgehammer999
7971a25c2a Fix Travis macOS builds. 2017-03-03 01:46:55 +02:00
Eugene Shalygin
ab2411930a Workaround problem with moc from Qt4 and #if
moc from Qt4 ignores Q_ENUMS when it is behind #if QT_VERSION check.
Therefore moc entries for enum in TorrentFileGuard were not generated
and the setting was not saving/loading. This closes #6103, #5451
2017-03-03 01:46:54 +02:00
sledgehammer999
93f972bfca Allow build failures for qt4 and osx for Travis. 2017-03-03 01:46:31 +02:00
sledgehammer999
db638844d0 Use custom qt5 bottle for homebrew (macOS) on Travis. 2017-03-03 01:46:30 +02:00
sledgehammer999
ba99eddc91 Add template for issues. 2017-03-03 01:46:29 +02:00
Eugene Shalygin
92428cee5d Set upper version limit for QTBUG-52633
The bug seems to be fixed in version 5.7.1.
2017-03-03 01:46:28 +02:00
sledgehammer999
2c7d836925 Don't use hardcoded numbers to refer to columns. 2017-03-03 01:46:27 +02:00
sledgehammer999
7703dcf626 Allow to change priority for unselected files through the combobox like it is done via the context menu. 2017-03-03 01:46:09 +02:00
sledgehammer999
157520c4fc Always show progress and remaining bytes for unselected files. 2017-03-03 01:46:08 +02:00
sledgehammer999
5bc728fa33 Use a disabled progressbar's palette for unselected files.
Thanks to evsh(Eugene Shalygin) for example code.
2017-03-03 01:46:07 +02:00
sledgehammer999
35fdc43b3f Update gpg key with new uid. 2017-03-03 01:46:05 +02:00
Eugene Shalygin
ae6ea29f2f cmake: make prefix variables cached
This allows user to override their default value via -D cmake switch
2017-03-03 01:46:04 +02:00
sledgehammer999
4eac2cab31 Bump to 3.3.10 2016-12-17 19:57:52 +02:00
sledgehammer999
87f4f57f8e Update Changelog. 2016-12-17 19:54:49 +02:00
sledgehammer999
a6e250fa43 WINDOWS: Make the updater to look for the x64 installer if running x64 version. 2016-12-17 19:48:46 +02:00
Oke Atime
b118079379 Make resume/pause menu items clickable. Closes #6040 2016-12-17 19:48:45 +02:00
Oke Atime
cb2d39f2a7 Case insensitive sort for client clumn. Closes #6054 2016-12-17 19:48:45 +02:00
sledgehammer999
4cf549ff25 Fix share ratio limiting. Broken by commit 259b5e51c4. Closes #6039 #6048. 2016-12-15 00:06:04 +02:00
sledgehammer999
b5c6342dca Bump to 3.3.9 2016-12-14 18:39:40 +02:00
sledgehammer999
46ec556921 Update Changelog. 2016-12-14 18:37:07 +02:00
sledgehammer999
33ae1a7bee Correctly migrate settings/rss/usage stats in macOS. Closes #6041. 2016-12-14 18:19:20 +02:00
sledgehammer999
87a3a67668 Fix GUI for proxy settings. Closes #6045. 2016-12-14 18:19:19 +02:00
sledgehammer999
055b1e0163 Fix slider for per torrent speed limits when no global speed limit has been set. Closes #6046. 2016-12-14 18:19:19 +02:00
sledgehammer999
2bd5ea2c68 Bump to 3.3.8 2016-12-14 02:13:13 +02:00
sledgehammer999
1479a74198 Update Changelog. 2016-12-14 02:10:00 +02:00
Eugene Shalygin
9a0d25284c Add a workaround for QTBUG-52633, qBt issue #5073
The QTBUG-52633 results in food of network interface changed events, libtorrent IP
rebind calls and flood in the qBt log. The work around is the check not only for
interface name, but for IP address on that interface before triggering the libtorrent rebind.
2016-12-14 02:04:12 +02:00
sledgehammer999
284e836992 New translations: Icelandic, Latvian, Malay, Occitan, Uzbek
Also re-run lupdate.
2016-12-13 02:11:45 +02:00
sledgehammer999
43f5b31843 Sync translations from Transifex and run lupdate. 2016-12-13 02:11:44 +02:00
sledgehammer999
cada6cfc88 Bump API_VERSION and API_VERSION_MIN to 11. 2016-12-13 02:11:43 +02:00
sledgehammer999
99f157927f Polish previous commit. 2016-12-12 21:17:18 +02:00
Yez Ezey
664664394c Change QSettings to IniFormat on macOS. Closes #5770 #5808
On macOS 10.12 Sierra, Apple changed the behaviour of CFPreferencesSetValue()
truncating data after a null character. https://bugreports.qt.io/browse/QTBUG-56344
Due to this, we have to move from native plist to IniFormat.
2016-12-12 21:17:17 +02:00
dzmat
a790901691 minimizing the number of warnings about deprecated auto_ptr 2016-12-12 21:17:17 +02:00
Chocobo1
fdc70eaa62 Change Utils::Fs::freeDiskSpaceOnPath() signature
refactor the function internals
2016-12-12 21:17:17 +02:00
Chocobo1
b05a23e1ab Remove unused variable 2016-12-12 21:17:16 +02:00
Chocobo1
9f6a0882e2 Simplify #if expression 2016-12-12 21:17:16 +02:00
Chocobo1
b351b21e55 Fix memory leak
call unicode version of the function directly
2016-12-12 21:17:16 +02:00
Chocobo1
ef22f06e92 Simplify function call 2016-12-12 21:17:16 +02:00
Chocobo1
8ea7426bc1 Replace deprecated classes 2016-12-12 21:17:15 +02:00
Chocobo1
79e7e1727f Fix unused variable warnings 2016-12-12 21:17:15 +02:00
Chocobo1
98c33dd77c Rename splitter names 2016-12-12 21:17:15 +02:00
Chocobo1
9c6504f6dd Use new key for storing RSS splitter_v value.
So that old value won't override the RSS layout.
2016-12-12 21:17:14 +02:00
Chocobo1
76c350bdcb Change RSS view layout to horizontal. Closes #5920.
Thanks Bhaalspawn for the idea.
2016-12-12 21:17:14 +02:00
sledgehammer999
106dcfd00e Decouple dependency between Session and BandwidthScheduler during Session init. Closes #6007. 2016-12-12 21:17:14 +02:00
sledgehammer999
668c8cb0e2 Fix travis osx build. 2016-12-12 21:17:14 +02:00
Chocobo1
3159bdf4dd Fix warning C4090.
different '__unaligned' qualifiers.
2016-12-12 21:17:13 +02:00
Chocobo1
97d2c0d187 Fix warning C4267.
conversion from 'size_t' to 'int', possible loss of data.
2016-12-12 21:17:13 +02:00
zywo
0041ee3636 Fix CMake compilation error. 2016-12-12 21:17:13 +02:00
Chocobo1
1ed523bec3 Shift + scroll = horizontal scroll, Closes #5980
Only for TransferListWidget, PeerListWidget
2016-12-12 21:16:39 +02:00
dzmat
b131a6e9df memleak fix 2016-12-12 21:16:39 +02:00
Chocobo1
56d9d370e9 Rename 2016-12-12 21:16:39 +02:00
Chocobo1
a6efc4d92d Fix URL 2016-12-12 21:16:38 +02:00
sledgehammer999
a77db6e822 Sync translations from Transifex and run lupdate. 2016-12-12 21:16:37 +02:00
Yez Ezey
95a558941e Fix downloadFromURL bug. Closes #5844 2016-12-12 21:16:37 +02:00
sledgehammer999
867d69d0f2 Travis: Use custom libtorrent formula and bottle for OSX.
Caches libtorrent 1.0.10 built with c++11 enabled.
2016-12-12 21:16:37 +02:00
sledgehammer999
a6d381da38 Option to disable tracker's favicon download. 2016-12-12 21:16:36 +02:00
sledgehammer999
f0eb708b07 Remove (mostly) useless log warnings about tracker's favicon. 2016-12-12 21:16:36 +02:00
Yez Ezey
1d70698bd0 add /usr/local/include due to Qt 5.7.0 bug on macOS 2016-12-12 21:16:36 +02:00
Chocobo1
79871c8e21 Update ax_boost_system.m4 to d48ec2210047bbf17702700811c3f16a5369e06c 2016-12-12 21:16:36 +02:00
Chocobo1
25d5524213 Remove redundant command 2016-12-12 21:16:35 +02:00
EdwardLinux
8d21b73434 Update portuguese.nsi 2016-12-12 21:16:35 +02:00
sledgehammer999
2ef01a314c Small travis update for OSX. 2016-12-12 21:16:35 +02:00
Yez Ezey
a8b4aca5e6 Set /usr/local/bin before default PATH on macOS. closes #5639 #5571
Since Apple made difficult for users to set PATH and /usr/bin/python
is almost unusable, I simply add /usr/local/bin before default PATH
to pick up Homebrew Python.
2016-12-12 21:16:35 +02:00
Anton Lashkov
67e7315eae Fix name of variable same as class member 2016-12-12 21:16:34 +02:00
Anton Lashkov
a25a15d1c6 Simplify if statement 2016-12-12 21:16:34 +02:00
Anton Lashkov
086588eeed Add missing else 2016-12-12 21:16:34 +02:00
Anton Lashkov
44fa308681 Fix mistake in getting value from model 2016-12-12 21:16:33 +02:00
Yez Ezey
6188287094 Add --disable-qt-dbus to configure if $host_os is macOS 2016-12-12 21:16:33 +02:00
Yez Ezey
17d10afd65 Sort torrent names case insensitively 2016-12-12 21:16:33 +02:00
Chocobo1
89bd0e4397 QJson: update to 5e3b9b84b225f4612e09ef05aa6d8c23379e4e71 2016-12-12 21:16:33 +02:00
Yez Ezey
1c1917f885 Fix extratorrent searchengine. Closes #5773
They changed to magnet link.
2016-12-12 21:16:32 +02:00
thalieht
642377bd65 Log: set embedded Tracker [OFF] msg type as info 2016-12-12 21:16:32 +02:00
Chocobo1
bb4668c071 Fix potential crash. Closes #5873. 2016-12-12 21:16:32 +02:00
Chocobo1
689316db09 Refactor 2016-12-12 21:16:32 +02:00
borouhin
ad0c008a3e Don't request client SSL certificate (closes issue #3883) 2016-12-12 21:15:51 +02:00
sledgehammer999
09e3698b37 Don't ever stop seeding forced torrents. Closes #5784. 2016-12-12 21:15:51 +02:00
sledgehammer999
6450ebfc6c Don't revert save path value in the Dialog when metadata are received. Closes #5482. 2016-12-12 21:15:51 +02:00
sledgehammer999
e9f38ebcfd Some more compiler warnings fixed. 2016-12-12 21:15:50 +02:00
sledgehammer999
4dba31f534 Fix warning due to stupid typo. 2016-12-12 21:15:50 +02:00
sledgehammer999
04c1aad0dd Delete old rss favicon before assigning new one. 2016-12-12 21:15:50 +02:00
sledgehammer999
6763f3ac33 WINDOWS: Fix python auto install, deletion of installer and use 3.5.x series for Vista+. Closes #5871. 2016-12-12 21:15:50 +02:00
sledgehammer999
afca704db0 WEBUI: Changed meaning of the value of the 'dl_limit', 'up_limit', 'alt_dl_limit' and 'alt_up_limit' tokens.
The value is expressed in bytes and not in KiB.
2016-12-12 21:15:49 +02:00
sledgehammer999
eaec8fcddd Fix setting a speed limit. 2016-12-12 21:15:49 +02:00
sledgehammer999
f86fd52d6f Add libtorrent's DHT bootstrap node to our bootstrap list. 2016-12-12 21:15:49 +02:00
sledgehammer999
f3f175570c Use the new API to add DHT bootstrap nodes for libtorrent 1.1.x and simplify the code a bit. 2016-12-12 21:15:49 +02:00
sledgehammer999
729c80f910 Use new libtorrent 1.1.2+ utility function to generate client ID instead. 2016-12-12 21:15:48 +02:00
sledgehammer999
fcaca558a0 Make sure that paths are loaded/saved using slashes as dir separators. 2016-12-12 21:15:48 +02:00
sledgehammer999
983df9113e Display message about libtorrent plugins for the correct case. 2016-12-12 21:15:48 +02:00
sledgehammer999
acf9874252 Migrate last setting related to interfaces to the new system. 2016-12-12 21:15:48 +02:00
sledgehammer999
d7cf6bb11b Fix save/load of interface address setting. 2016-12-12 21:15:47 +02:00
sledgehammer999
558ea53cc2 Use better variable names for tracker announce IP setting. 2016-12-12 21:15:47 +02:00
sledgehammer999
87a6478430 Fix values for unsetting speed limits. 2016-12-12 21:15:47 +02:00
sledgehammer999
cea673b267 Unify and simplify setting to use proxy for torrents only. 2016-12-12 21:15:46 +02:00
sledgehammer999
4a5ab93c62 Guard the flag used for deferred session configure. 2016-12-12 21:15:46 +02:00
sledgehammer999
4c86fc8973 Misc fixes. 2016-12-12 21:15:46 +02:00
sledgehammer999
1c485ffb07 Fix setting limits to unlimited. 2016-12-12 21:15:46 +02:00
sledgehammer999
f283734f13 Rename IP filtering functions and settings names. 2016-12-12 21:15:45 +02:00
sledgehammer999
dca4ff0649 Export torrents added only after the setting was enabled. 2016-12-12 21:15:45 +02:00
Vladimir Golovnev (Glassez)
1975f2269e Use new libtorrent-1.1 settings API 2016-12-12 21:15:42 +02:00
Vladimir Golovnev (Glassez)
6fac9b42da Don't use Preferences in BitTorrent::Session 2016-12-12 21:12:01 +02:00
DaRKSoM
dabae4c914 Update portugueseBR.nsi 2016-12-12 21:11:20 +02:00
Burak Yavuz
b1e9b4493d Turkish translation 2016-12-12 21:11:19 +02:00
Chocobo1
2fa207e728 The intended action is set the bit to 1, not flipping it. 2016-12-12 21:11:19 +02:00
Chocobo1
7adcd909e7 Fix crash when restoring from tray. Closes #5854. 2016-12-12 21:11:19 +02:00
ngosang
50805fc2b5 [Search engine] Remove TorrentReactor plugin 2016-12-12 21:11:19 +02:00
ngosang
3a1b7b6159 [Search engine] Update Demonoid plugin 2016-12-12 21:11:18 +02:00
sledgehammer999
498b7c2436 Properly fix the handling of default save path store/load. Bug introduced in dd34663224 2016-12-12 21:11:18 +02:00
erikssm
4f17364305 fix default save path bug 2016-12-12 21:11:18 +02:00
Yez Ezey
9ebc115719 Fix Mac OS X Build (Closes #5763)
Deleted offending code
    setUnifiedTitleAndToolBarOnMac(false);
which was a workaround to avoid bug https://bugreports.qt.io/browse/QTBUG-7305
The bug was fixed at Qt 4.6.2 https://github.com/Blizzard/qt4/blob/master/dist/changes-4.6.2
2016-12-12 21:11:17 +02:00
Yez Ezey
a6fa8c3a8e Fixed extratorrent search not working Closes #5736 #5753
The original code accumulates all the <td> texts between the description
link and the number of seeders into self.current_item["size"]:
    <td>248.72</td><td>&nbsp;MB<td> => "248.72 MB".
ExtraTorrents changed the table design, added the Added column and joined
the number and its unit:
    <td>8d</td><td>248.72&nbsp;MB</td> => "8d 248.72 MB"
This commit stores only the last <td> text in self.current_item["size"].
2016-12-12 21:11:17 +02:00
sledgehammer999
8187366c89 Use a subdomain to redirect to the actual URL for search plugins.
Will allow to move around the plugins in the git repo with the 3.4.0 release.
2016-12-12 21:11:16 +02:00
thalieht
366ad01120 fix webui port overflow 2016-12-12 21:11:16 +02:00
sledgehammer999
4da05e5914 Update UAC nsis plugin to 0.2.4c. Building the installer with nsis 3.0 (final) is possible now. Closes #5556. 2016-09-12 17:31:42 +03:00
sledgehammer999
3fb19b6a28 Fix travis again.
I wish the homebrew guys didn't break it so often and the travis guys updated their images more frequently.
2016-09-12 02:46:48 +03:00
242 changed files with 106277 additions and 55088 deletions

View File

@@ -9,8 +9,8 @@ environment:
REPO_DIR: &REPO_DIR c:\qbittorrent
CACHE_DIR: &CACHE_DIR c:\qbt_cache
QBT_VER_URL: http://builds.shiki.hu/appveyor/version
QBT_LIB_URL: http://builds.shiki.hu/appveyor/qbt_libraries.7z
QBT_VER_URL: https://builds.shiki.hu/appveyor/version
QBT_LIB_URL: https://builds.shiki.hu/appveyor/qbt_libraries.7z
# project directory
clone_folder: *REPO_DIR

14
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,14 @@
**Please provide the following information**
### qBittorrent version and Operating System:
### If on linux, libtorrent and Qt version:
### What is the problem:
### What is the expected behavior:
### Steps to reproduce:
### Extra info(if any):

View File

@@ -3,7 +3,7 @@ language: cpp
os:
- linux
- osx
osx_image: xcode7
osx_image: xcode7.3
env:
matrix:
@@ -17,6 +17,12 @@ env:
global:
- secure: "OI9CUjj4lTb0HwwIZU5PbECU3hLlAL6KC8KsbwohG8/O3j5fLcnmDsK4Ad9us5cC39sS11Jcd1kDP2qRcCuST/glVNhLkcjKkiQerOfd5nQ/qL4JYfz/1mfP5mdpz9jHKzpLUIG+TXkbSTjP6VVmsb5KPT+3pKEdRFZB+Pu9+J8="
- coverity_branch: coverity_scan
matrix:
allow_failures:
- os: osx
env: lt_branch=RC_1_0 qt=4 gui=true
- os: osx
env: lt_branch=RC_1_0 qt=4 gui=false
branches:
except:
@@ -30,7 +36,10 @@ notifications:
# container-based builds
#sudo: false
cache: ccache
cache:
ccache: true
directories:
- $HOME/hombebrew_cache
# opt-in Ubuntu Trusty
sudo: required
@@ -117,16 +126,40 @@ install:
fi
- |
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
wget https://builds.shiki.hu/homebrew/version ;
if ! cmp --quiet "version" "$HOME/hombebrew_cache/version" ; then
echo "Cached files are different from server. Downloading new ones." ;
# First delete old files
rm -r "$HOME/hombebrew_cache" ;
mkdir "$HOME/hombebrew_cache";
cp "version" $HOME/hombebrew_cache ;
cd "$HOME/hombebrew_cache" ;
wget https://builds.shiki.hu/homebrew/libtorrent-rasterbar.rb ;
wget https://builds.shiki.hu/homebrew/libtorrent-rasterbar-1.0.10.el_capitan.bottle.tar.gz ;
wget https://builds.shiki.hu/homebrew/qt5.rb ;
wget https://builds.shiki.hu/homebrew/qt5-5.7.1_1.el_capitan.bottle.tar.gz ;
fi
# dependencies
brew update > /dev/null ;
brew install colormake ccache ;
brew outdated "pkg-config" || brew upgrade "pkg-config" ;
# libtorrent-rasterbar 1.0.9
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/477d5060fa093883204d70323965375353e03084/Formula/libtorrent-rasterbar.rb ;
# Copy custom libtorrent bottle to homebrew's cache so it can find and install it
# Also install our custom libtorrent formula by passing the local path to it
# These 2 files are restored from Travis' cache.
cp "$HOME/hombebrew_cache/libtorrent-rasterbar-1.0.10.el_capitan.bottle.tar.gz" "$(brew --cache)" ;
brew install "$HOME/hombebrew_cache/libtorrent-rasterbar.rb" ;
# Qt
if [ "$qt" = 4 ]; then brew install qt && ln -s /usr/local/Cellar/qt/4.8.7_2/plugins /usr/local ; fi ;
if [ "$qt" = 5 ]; then brew install qt5 && brew link --force qt5 && ln -s /usr/local/Cellar/qt5/5.6.0/plugins /usr/local ; fi ;
if [ "$qt" = 5 ]; then
# Copy custom qt5 bottle to homebrew's cache so it can find and install it
# Also install our custom qt5 formula by passing the local path to it
# These 2 files are restored from Travis' cache.
cp "$HOME/hombebrew_cache/qt5-5.7.1_1.el_capitan.bottle.tar.gz" "$(brew --cache)" ;
brew install "$HOME/hombebrew_cache/qt5.rb" ;
brew link --force qt5 ;
fi
# ccache
if [ "$TRAVIS_BRANCH" != "$coverity_branch" ]; then

View File

@@ -26,28 +26,67 @@ HiShCTSSDBJqFmhfjrCo0nISKnzyxgO/rY9vFlwXsKkTyL7s53ONkjwK34WmGnya
tXdjBWShzAiTfF5hephfBSszmoBG2C8Jcu6P5n4buBY4RCsEa+6jE0R1vCtmpVwx
WrXOeN2kGYMpAkPK1L69Le0FofgUDKlaFMv7KRl4R367xNRukYrsKwVlontJ+Y72
X5t1BeRn8VSp0IzhssNXM8a4bTE8lvs889DOS2vgWEHIi0iyIesJYWPs4AKUw4rG
EDwWxtTS0a7Rfx3DxLkCDQRXDSCMARAAqMIVJizEJp205c546IN75xeYiFszNXcs
3768IY8bOoWj+rTwt2wIwtL/3O5K2dG79CSt2H5o6BPKmq43tOO60YW3Yk3m9BB/
gnAVqk0QOPr5O8+yeBzdElU8CZh6y6zZMWugSkNmTDm6jZzPhgNjcjrit/dl9+0D
GqJQcqoD8WzEWNcWrMHVz9cDewnLSVkwR758mZMaIiL7R10MZ++tNrC0j69UINqx
+9z1r1J07+NNnxqSTxVRcbjPYtM9E+tUiVFS2HPWN9ShVDkBAEdoWh90qzRaMiFl
2NGNGOD1iHx/xr06RMeGEEXt2vhSlhfMW2YQW+UD2jzlFbARf53v39MUKKscGuIp
BhxGw3JCq4l6qLW/bDkgnoXlOhZDmhQm6OpsjAyk9IEdd3ponSc7yYD3mUkJKR9e
TaALD5t6TQGyNHakb4UfoXtE2RR78cbPlLIwag7eQ8GsNA+dfjowmOZdojx3ROsH
ZdGQwb0YFLjuKAusA3TY+lCfbS6kzE2iI2DuaW+3dICcLrYuibbVb0CBNHyD+8KE
tczdur/wm0lhqyVJkGyZKZT8C2cPxywKgy1Rn6F8Yfmj0Lna3nvtaZu0ZUS4/8Li
t5PcOso1lSmYBuD6yq+GEAMCnUmn1Pm8eZRMlxxQuTPvyJKQrRDhbtAAr472MSno
JKlS4SfaUF0AEQEAAYkCHwQYAQgACQUCVw0gjAIbDAAKCRBuSi0CW3zJomZDD/9I
Jmzd5hiEzntlp84pyIJcfyIRe4KImvldAy6T02OSIbF1HzCNnwmqIPob6MOdMZ+K
NwMK0htRkrRr/zM034+lBiWKZt+tVYHu49ioTYXEjAc5qDJE09Sq7HceQnhgE48f
1n54XGT5G2w5gw+/a8Qn1SceE44VwXafL3E1gKaOrrsb1UH/AJhp+W4VMu+7bLXu
7h1tN6v2PhvCYvBt3zyy8Q8xfJ2x7/D1lbF8ATJAiZ/km9x5bRm7OGRliVYaUe1n
yR42fZOj3CBmAR0+lZLgjriqdMXrs+qlBbrmAhkn0XPQXAeaPifKoKIGDAUWIsqD
HqM7imMGT+MR9APfSw8M4enOJWL+HnKpVBEARCEDpaFpJ3u7QRucFybpEhvIymoN
ftyw+urId2Eg2K33NypeZo3M1K2LC65f2Ta7f/sZcIDUTbgW+m334fgVl1KptDA5
DX3U9lTci7mi4uPuAFtbWrB1di4jYrxXYuzFm5g4xTb0Hw3kYIB6WXF+I7i0JaGO
THxPC5X5lIAZrYrkxh+1n1Y1CY+TC8JcTzwORJIbFFm9tD/BHXa4849k4DVvFYCZ
khq+/56FKZfoVByhB+x+2GaMlsBm1uPniO4lAakFPpIi0kaap4UVayQ/7ak+Bhsc
AIHZUy6NtgZkuvW3xdpwp07LYo2ilhMI8RnzmtoRmg==
=tDGM
EDwWxtTS0a7Rfx3DxLRWc2xlZGdlaGFtbWVyOTk5IChVc2VkIGZvciBzaWduaW5n
IGdpdCBjb21taXRzL3RhZ3MvZXRjLikgPGhhbW1lcmVkOTk5QHFiaXR0b3JyZW50
Lm9yZz6JAh8EMAEIAAkFAlhie1ICHQAACgkQbkotAlt8yaILIhAAp25o1BbUG2Zk
At3cSrTFnZSCA7nEygbSUv1Uek33JZfY0Apw5qEM8lQCMZk+mhdrSQCYUJcQlruN
zJcJf4CH+VGE23xkI3Kf0nGp9Cjn/q6b1hLIPe5rimvw5pTAejFtebcYY/ZJIB8Z
H1ebuzfqBZ/9k7eYTarZ/ZsgG8YptB0RXBQWOMaSEKwdeo2m7HXHgK3blQiqbuJJ
uyPbid01Wus4AVN47/FKgDNswPs8irYZsu5yakgpi2KLycGDtSiN5XFHI4xbC0zM
srR7Cz0/fC+klhGcuxbw0V0It7UUIitgCcTPHXkukUU8i2+AGMyKa1HjchsXDdLg
DIs6KIurp2ve7znKOz7h1aX8cOBmB/QYeYAx9jRRkePMIRT8V1lRwfvJlJxx1+G3
e2gJLjqTN8a08KHHjdY/S0ZFERxSlmOym2uf/y6di1ipDPxo8xvDuS5kDbdZLC0t
XijlsH8ONK27KNuWhucG8zHzKQvnPw2qN06SZq4FjbSmAkkuYs56heLEXMzFr75k
SE8rUoQQ+ABG9gU46GEvKlZxqSwXgGnb1X6K7h8svjMh/NlAU358p8Sra4Ru5tz4
jUu9MoVEw5Lbjcrsnp6/4Kk1Q2ckBNt43nv8/+C7NsC3xi6BrOInuaKHZ4QsTuzJ
m1/A4zlKRnUi6T98DXfIYnNuV9NSmAWJAjkEEwEIACMFAlhiemMCGwMHCwkIBwMC
AQYVCAIJCgsEFgIDAQIeAQIXgAAKCRBuSi0CW3zJor6yD/9N2U0INx0nYpGkmvah
yVG/vw2S6hhKK+03AN+RrtddNRg4aBf/gmOvRWQhAmFnXOBA7fO09wgcljaV5tVb
MYyYZvHhK0o2/sli2p/M5N8ZxchRHypjxUSEyG9ZQ06QG5DVhh4HtM8nIN+UcwTV
C5QjyoWZvHf+tNroyFeh7zT+w4kX1VxgynTQr5LGdYsrVA3CFyT3zsBWV3dMae23
22CHOirsBBLwairHUsWW+BdThT3MkKYpTEV0jkH4OyAXhJYcS5IjjtKQ8UpZE9dw
f4saJ0TnXNe7goPRZtH7UjPwfVbtYK4y8QklWUTRxgoBxNwSC5X7Flg+3xXxE/VU
U4cehyRkH64i7MJDoFkqh5JtjkgIz+kuTTXb7xR0Wf+JXrGMybZTR8xth2TEMC20
1FT5L5+0vH1WRzL7bhlaU3EXyCnoH8sDvMEClZbibbew+rf7fC3tFU41ohUT0HDl
zlyfVjRvBHWMTgfpWKBV2m/qP941xTJ9VHxOlAB02XKUZYwFt07CpH+yjMOCOzA4
cTPBD3mGRuft0V0BJ8bA5bcTly/GBciRX0Y5oIeHZGgq2czb0sywSYT6mPoQMFNM
B+Cwr4pm90r1DMMfW518onF2itwyN/Id0FsWDhsLJHKluBJw52C3OnxCuToVutTm
xntqpPVv62LaeVeWQqxIieTJErRQc2xlZGdlaGFtbWVyXzk5OSAoVXNlZCBmb3Ig
c2lnbmluZyBnaXQgY29tbWl0cy90YWdzL2V0YykgPGhhbW1lcmVkOTk5QGdtYWls
LmNvbT6JAjkEEwEIACMFAlhifeICGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIX
gAAKCRBuSi0CW3zJolcCD/9xPBNEkFtnhTW89th0TFZnB5oykCQjyefquvQs8KWT
C92/1VizHi4ZxDehHWP9IKVWT3ZJthj5ZXBSedyl1tHnwkyrUYBW9roQwtDWPncK
pXl/HsE6p3q6EIus+g6YJo4UvYachJFAZATZp1WDBPIswziHGzaL0tndFWZuVM8V
QD0tfPQsS1qCDVv6+B1JWZDnA1JzdSG/uzPhL95q/ff6JmNbfSAVedK2PyqYshnC
KWBx6Yna/0ColBuDFho8+bDuHPQcM35xyjPosVD7moXQiY4yMAJ+VzwEBaCFleI0
RBWw8/+qyoFqfIKwdq8G+7I9LjWpBiN2+uQBZ+OAvsMWyRShLopxt3JluPTtL6xb
Ca6dglOdlaOS/A6FK7u05k/8kQMDS5Jq2/rpfTPRl1/weCaJZgfRIBosk1Mon/pR
p1zd0abM4t7BcGQpwSkKAmqlKCrWf886EFQT0CJTBo8q7pzgpVraWWPVsmAOdkfU
YcKBgz1A2uMSAxypkSzaDZkIVj6I7gwiGk7IMYx1OK7Ev46h/x4Z7kgT0y3DYYOq
ggVEKQ+15Krn7bZ35s8vbZdfnVKPSXdCC8jkIMBmGmRX6cgZZ3OXZlrrHht5icgJ
5Z2d1M4JUoEZVUr2xNZkkaMk01NAIpGgKvIS6yHuj6vE4GMJ+A/qEW6J60/3YHRe
0bkCDQRXDSCMARAAqMIVJizEJp205c546IN75xeYiFszNXcs3768IY8bOoWj+rTw
t2wIwtL/3O5K2dG79CSt2H5o6BPKmq43tOO60YW3Yk3m9BB/gnAVqk0QOPr5O8+y
eBzdElU8CZh6y6zZMWugSkNmTDm6jZzPhgNjcjrit/dl9+0DGqJQcqoD8WzEWNcW
rMHVz9cDewnLSVkwR758mZMaIiL7R10MZ++tNrC0j69UINqx+9z1r1J07+NNnxqS
TxVRcbjPYtM9E+tUiVFS2HPWN9ShVDkBAEdoWh90qzRaMiFl2NGNGOD1iHx/xr06
RMeGEEXt2vhSlhfMW2YQW+UD2jzlFbARf53v39MUKKscGuIpBhxGw3JCq4l6qLW/
bDkgnoXlOhZDmhQm6OpsjAyk9IEdd3ponSc7yYD3mUkJKR9eTaALD5t6TQGyNHak
b4UfoXtE2RR78cbPlLIwag7eQ8GsNA+dfjowmOZdojx3ROsHZdGQwb0YFLjuKAus
A3TY+lCfbS6kzE2iI2DuaW+3dICcLrYuibbVb0CBNHyD+8KEtczdur/wm0lhqyVJ
kGyZKZT8C2cPxywKgy1Rn6F8Yfmj0Lna3nvtaZu0ZUS4/8Lit5PcOso1lSmYBuD6
yq+GEAMCnUmn1Pm8eZRMlxxQuTPvyJKQrRDhbtAAr472MSnoJKlS4SfaUF0AEQEA
AYkCHwQYAQgACQUCVw0gjAIbDAAKCRBuSi0CW3zJomZDD/9IJmzd5hiEzntlp84p
yIJcfyIRe4KImvldAy6T02OSIbF1HzCNnwmqIPob6MOdMZ+KNwMK0htRkrRr/zM0
34+lBiWKZt+tVYHu49ioTYXEjAc5qDJE09Sq7HceQnhgE48f1n54XGT5G2w5gw+/
a8Qn1SceE44VwXafL3E1gKaOrrsb1UH/AJhp+W4VMu+7bLXu7h1tN6v2PhvCYvBt
3zyy8Q8xfJ2x7/D1lbF8ATJAiZ/km9x5bRm7OGRliVYaUe1nyR42fZOj3CBmAR0+
lZLgjriqdMXrs+qlBbrmAhkn0XPQXAeaPifKoKIGDAUWIsqDHqM7imMGT+MR9APf
Sw8M4enOJWL+HnKpVBEARCEDpaFpJ3u7QRucFybpEhvIymoNftyw+urId2Eg2K33
NypeZo3M1K2LC65f2Ta7f/sZcIDUTbgW+m334fgVl1KptDA5DX3U9lTci7mi4uPu
AFtbWrB1di4jYrxXYuzFm5g4xTb0Hw3kYIB6WXF+I7i0JaGOTHxPC5X5lIAZrYrk
xh+1n1Y1CY+TC8JcTzwORJIbFFm9tD/BHXa4849k4DVvFYCZkhq+/56FKZfoVByh
B+x+2GaMlsBm1uPniO4lAakFPpIi0kaap4UVayQ/7ak+BhscAIHZUy6NtgZkuvW3
xdpwp07LYo2ilhMI8RnzmtoRmg==
=UBeB
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -1,15 +1,14 @@
cmake_minimum_required(VERSION 3.5)
cmake_policy(VERSION 3.5)
project(qBittorrent VERSION 3.4.0.0)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules)
include(FunctionReadVersion)
set(VER_MAJOR ${qBittorrent_VERSION_MAJOR})
set(VER_MINOR ${qBittorrent_VERSION_MINOR})
set(VER_BUGFIX ${qBittorrent_VERSION_PATCH})
set(VER_BUILD ${qBittorrent_VERSION_TWEAK})
set(VER_STATUS "alpha") # Should be empty for stable releases!
read_version("${CMAKE_CURRENT_SOURCE_DIR}/version.pri" VER_MAJOR VER_MINOR VER_BUGFIX VER_BUILD VER_STATUS)
# message(STATUS "Project version is: ${VER_MAJOR}.${VER_MINOR}.${VER_BUGFIX}.${VER_BUILD} (${VER_STATUS})")
project(qBittorrent VERSION ${VER_MAJOR}.${VER_MINOR}.${VER_BUGFIX}.${VER_BUILD})
# Don't touch the rest part
set(PROJECT_VERSION "${VER_MAJOR}.${VER_MINOR}.${VER_BUGFIX}")
if (NOT VER_BUILD EQUAL 0)
@@ -28,7 +27,6 @@ add_definitions(-DVERSION_BUILD=${VER_BUILD})
# } else {
add_definitions(-DVERSION="v${PROJECT_VERSION}")
# }
list(APPEND CMAKE_MODULE_PATH ${qBittorrent_SOURCE_DIR}/cmake/Modules)
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Og")
if (UNIX AND NOT APPLE)

127
Changelog
View File

@@ -1,3 +1,130 @@
* Fri Mar 03 2017 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.3.11
- FEATURE: Always show progress and remaining bytes for unselected files. (sledgehammer999)
- FEATURE: Allow to change priority for unselected files through the combobox like it is done via the context menu. (sledgehammer999)
- FEATURE: Remove settings to exchange trackers. It wasn't used by non-libtorrent clients. Also it has a privacy risk and you might be DDoSing someone. (sledgehammer999)
- FEATURE: Put temp files in .qBittorrent directory. Closes #4462. (Chocobo1)
- FEATURE: Use the numbers from tracker scrape response. Closes #5048, #6117. (Chocobo1)
- FEATURE: Implement category filter widget. Show categories in tree mode when subcategories are enabled. (glassez)
- FEATURE: Allow to toggle columns in searchtab (thalieht)
- FEATURE: PeerList: allow to hide zero values for the "uploaded" and "downloaded" columns (thalieht)
- FEATURE: Display more information in tracker tab (ngosang)
- FEATURE: Use Ctrl+F to search torrents. Closes #5797. (Tim Delaney)
- FEATURE: Transferlist: add hotkeys for double click and recheck selected torrents (thalieht)
- FEATURE: Add hotkey for execution log tab, Trackerlist, Peerlist etc (thalieht)
- FEATURE: Seperate seeds from peers for DHT, PeX and LSD (thalieht)
- BUGFIX: Do not remove added files unconditionally. Closes #6248 (Eugene Shalygin)
- BUGFIX: Ignore mouse wheel events in Advanced Settings. Closes #866. (Chocobo1)
- BUGFIX: Add queue repair code. It should fix missing torrents after restarting. (Eugene Shalygin, nxd4)
- BUGFIX: Fetch torrent status when generating final fastresume data. It should fix missing torrents after restarting. (Eugene Shalygin)
- BUGFIX: Fix queue overload for add torrent at session start. It should fix missing torrents after restarting. (falco)
- BUGFIX: After files relocate, don't remove the old folder even if it is empty. (Chocobo1)
- BUGFIX: Fix finding 'English' item in language dropdown menu when an unrecognized locale is requested. Closes #6109. (sledgehammer999)
- BUGIFX: Speedlimitdlg: raise slider default value to 10000. Closes #6150. (Chocobo1)
- BUGFIX: TransferListWidget: keep columns width even if they are hidden on qBittorrent startup (unless something goes wrong) (thalieht)
- BUGFIX: fix index overflow for torrents with invalid meta data or empty progress (Falco)
- BUGFIX: Immediately update torrent_status after manipulating super seeding mode. Partially fixes #6072. (sledgehammer999)
- BUGFIX: Use case-insensitive comparsion for torrent content window. Closes #6327. (Chocobo1)
- BUGFIX: Fixed sort order for datetime columns with empty values (closes #2988) (Vladimir Sinenko)
- BUGFIX: Disable proxy in WebUI HTTP server. Closes #6349. (Eugene Shalygin)
- COSMETIC: Use a disabled progressbar's palette for unselected files. (sledgehammer999)
- COSMETIC: Support fallback when selecting theme icons (Eugene Shalygin)
- COSMETIC: Do not resize SVG icons (Eugene Shalygin)
- COSMETIC: Align text to the right in columns that handle numbers for PeerList and SearchTab (thalieht)
- COSMETIC: Increased number of digits after the decimal point for Gibibytes and above (thalieht)
- COSMETIC: Use non-breaking spaces between numbers and units (thalieht)
- WEBUI: Fix proxy type bug (Oke Atime)
- WEBUI: Use the correct value for KEY_TORRENT_NUM_COMPLETE/KEY_TORRENT_NUM_INCOMPLETE (Chocobo1)
- WEBUI: Make torrents table scrollable horizontally (buinsky)
- WEBUI: Make torrent peers table scrollable horizontally (buinsky)
- WEBUI: Add tooltips to dynamic table header (buinsky)
- WEBUI: Implement dynamic table columns resizing, reordering and hiding (buinsky)
- WEBUI: Add some missing columns to dynamic tables (buinsky)
- WEBUI: Make too tall menus scrollable (buinksy)
- WEBUI: Prevent text wrapping in menus (buinsky)
- WEBUI: Add a vertical separator between columns (buinsky)
- WEBUI: Implement resizable progress bar in "Done" column (buinsky)
- WEBUI: Fix scrollbar covers menu item with long text (buinsky)
- WEBUI: Remove 300px limit of column width (buinsky)
- WEBUI: Avoid lags in firefox on resizing progress column (buinsky)
- WEBUI: Fix category in torrent upload. Closes #6260 (ngosang)
- WEBUI: Turn off port forwarding of WebUI by default for GUI users (Chocobo1)
- WEBUI: Exclude insecure ciphers. Fixes security issues reported by @beardog108 privately. (Chocobo1)
- WEBUI: Avoid clickjacking attacks. Fixes security issues reported by @beardog108 privately. (ngosang)
- WEBUI: Add X-XSS-Protection, X-Content-Type-Options, CSP header. Fixes security issues reported by @beardog108 privately. (Chocobo1)
- WEBUI: Escape various values that might contain injected html. Fixes security issues reported by @beardog108 privately. (Chocobo1)
- WEBUI: Bump API_VERSION to 12.
- SEARCH: Update extratorrent plugin. Closes #6261 (ngosang)
- SEARCH: SearchTab: can now save sorting column changes (thalieht)
- SEARCH: Use case-insensitive sort for Name column in Search tab. Closes #407. (Chocobo1)
- RSS: Fix tab order in RSS downloader. Closes #6164. (Tim Delaney)
- RSS: Move old RSS items to separate config file. Closes #6167. (Tim Delaney)
- RSS: Episode filter code refactoring (Tim Delaney)
- RSS: Allow resetting rule to no category. Closes #5539. (Tim Delaney)
- RSS: Save rule on enable/disable even if not selected. Closes #6163. (Tim Delaney)
- RSS: Allow | in RSS must contain. Closes #6171. (Tim Delaney)
- RSS: RSS use red text to indicate invalid filter. Closes #6165. (Tim Delaney)
- RSS: Allow episode zero (special) and leading zeroes in RSS episode filter. (Tim Delaney)
- RSS: RSS parse torrent episodes like 1x01 as well as S01E01. Closes #2749. (Tim Delaney)
- RSS: RSS allow infinite range to extend beyond current season. Closes #800, #3876, #6170. (Tim Delaney)
- RSS: Improve UI responsiveness during RSS downloading. Closes #873, #1089, #1235, #5423. (Tim Delaney)
- RSS: Show name of feed list and sort rules in editor. Closes #3782, #6281. (Tim Delaney)
- RSS: Fix regex matching. Closes #6337. (Tim Delaney)
- MACOS: Fix qbittorrent-nox build (Oke Atime)
- LINUX: fixes default indicator name (Bilal Elmoussaoui)
- OTHER: Workaround problem with moc from Qt4 and #if (Eugene Shalygin)
- OTHER: Print warning to the user if stacktrace contains no function names (Eugene Shalygin)
- OTHER: Various cmake fixes (Eugene Shalygin)
- OTHER: Fix finding qmake in configure when cross-compiling (Zach Bacon)
* Sat Dec 17 2016 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.3.10
- BUGFIX: Fix share ratio limiting. Broken by commit 259b5e51c49b744. Closes #6039 #6048. (sledgehammer999)
- BUGFIX: Case insensitive sort for client column. Closes #6054. (Oke Atime)
- BUGFIX: Make resume/pause menu items clickable. Closes #6040. (Oke Atime)
- WINDOWS: Make the updater to look for the x64 installer if running x64 version. (sledgehammer999)
* Wed Dec 14 2016 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.3.9
- BUGFIX: Fix slider for per torrent speed limits when no global speed limit has been set. Closes #6046. (sledgehammer999)
- BUGFIX: Fix GUI for proxy settings. Closes #6045. (sledgehammer999)
- OSX: Correctly migrate settings/rss/usage stats in macOS. Closes #6041. (sledgehammer999)
* Wed Dec 14 2016 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.3.8
- FEATURE: Start using new libtorrent 1.1.x APIs (needs at least 1.1.2). Still unofficial support. (glassez, sledgehammer999)
- FEATURE: Add a new DHT bootstrap node run by libtorrent author arvidn. (sledgehammer999)
- FEATURE: Option to disable tracker's favicon download. (sledgehammer999)
- FEATURE: Shift + scroll = horizontal scroll. Closes #5980. Only for TransferListWidget, PeerListWidget. (Chocobo1)
- BUGFIX: Actually set new path as default when checkBox is enabled in Add New Torrent dialog. (erikssm)
- BUGFIX: Properly fix the handling of default save path store/load. (sledgehammer999)
- BUGFIX: Fix crash when restoring from tray. Closes #5854. (Chocobo1)
- BUGFIX: Export torrents added only after the setting was enabled. (sledgehammer999)
- BUGFIX: Delete old rss favicon before assigning new one. (sledgehammer999)
- BUGFIX: Don't revert save path value in the Dialog when metadata are received. Closes #5482. (sledgehammer999)
- BUGFIX: Don't ever stop seeding forced torrents. Closes #5784. (sledgehammer999)
- BUGFIX: Fix potential crash in TransferList widget. Closes #5873. (Chocobo1)
- BUGFIX: Sort torrent names case insensitively. (Yez Ezey)
- BUGFIX: Fix mistake in getting values for sorting in TransferList widget. (Anton Lashkov)
- BUGFIX: Fix memory leaks. (dzmat, Chocobo1)
- WEBUI: Fix webui port overflow. (thalieht)
- WEBUI: Changed meaning of the value of the 'dl_limit', 'up_limit', 'alt_dl_limit' and 'alt_up_limit' tokens. The value is expressed in bytes and not in KiB. (sledgehammer999)
- WEBUI: Don't request client SSL certificate. Closes #3883. (borouhin)
- WEBUI: Bump API_VERSION and API_VERSION_MIN to 11.
- SEARCH: Fixed extratorrent search not working Closes #5736 #5753. (Yez Ezey)
- SEARCH: Update Demonoid plugin. (ngosang)
- SEARCH: Remove TorrentReactor plugin. (ngosang)
- SEARCH: Fix python auto install, deletion of installer and use 3.5.x series for Vista+. Closes #5871. (sledgehammer999)
- SEARCH: Set /usr/local/bin before default PATH on macOS. closes #5639 #5571. This enables finding newer python installs. (Yez Ezey)
- COSMETIC: Log: set embedded Tracker [OFF] msg type as info. (thalieht)
- COSMETIC: Remove (mostly) useless log warnings about tracker's favicon. (sledgehammer999)
- COSMETIC: Change RSS view layout to horizontal. Closes #5920. (Chocobo1)
- OSX: Fix crash on exit using Qt4. (Yez Ezey)
- OSX: Change QSettings to IniFormat on macOS. Closes #5770 #5808. (Yez Ezey)
- LINUX: Workaround a Qt5 bug which results in a flood of network interface change singals. (Eugene Shalygin)
- OTHER: Turkish translation for installer. (Burak Yavuz)
- OTHER: Update portugueseBR for installer. (DaRKSoM)
- OTHER: Update portuguese for installer. (EdwardLinux)
- OTHER: Add --disable-qt-dbus to configure if $host_os is macOS. (Yez Ezey)
- OTHER: New translations: Icelandic, Latvian, Malay, Occitan, Uzbek.
- OTHER: A whole lot of code refactoring by various people.
* Sun Sep 11 2016 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.3.7
- FEATURE: Delete torrent+files with Shift+Delete (pieniacy)
- BUGFIX: Fix 6-hour speedplot point push rate. Close #5545 (Daniel Segesdi)

View File

@@ -14,6 +14,11 @@
find_package(Threads REQUIRED)
find_package(PkgConfig QUIET)
macro(_detect_boost_components _outComponets librariesList)
string(REGEX MATCHALL "boost_[a-z_]+[-a-z]*" _boost_libraries "${librariesList}")
string(REGEX REPLACE "boost_([a-z_]+)[-a-z]*" "\\1" ${_outComponets} "${_boost_libraries}")
endmacro()
if(PKG_CONFIG_FOUND)
pkg_check_modules(PC_LIBTORRENT_RASTERBAR QUIET libtorrent-rasterbar)
endif()
@@ -62,13 +67,33 @@ endif()
set(LibtorrentRasterbar_LIBRARIES ${LibtorrentRasterbar_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})
set(LibtorrentRasterbar_INCLUDE_DIRS ${LibtorrentRasterbar_INCLUDE_DIR})
if(NOT Boost_SYSTEM_FOUND OR NOT Boost_CHRONO_FOUND OR NOT Boost_RANDOM_FOUND)
find_package(Boost REQUIRED COMPONENTS date_time system chrono random thread)
set(LibtorrentRasterbar_LIBRARIES
${LibtorrentRasterbar_LIBRARIES} ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
set(LibtorrentRasterbar_INCLUDE_DIRS
${LibtorrentRasterbar_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
endif()
# Without pkg-config, we can't possibly figure out the correct boost dependencies
if (LibtorrentRasterbar_CUSTOM_BOOST_DEPENDENCIES)
set(_boost_components "${LibtorrentRasterbar_CUSTOM_BOOST_DEPENDENCIES}")
else(LibtorrentRasterbar_CUSTOM_BOOST_DEPENDENCIES)
if(PC_LIBTORRENT_RASTERBAR_FOUND)
_detect_boost_components(_boost_components "${PC_LIBTORRENT_RASTERBAR_LIBRARIES}")
else()
# all possible boost dependencies
set(_boost_components
date_time
system
chrono
random
thread
)
endif()
endif(LibtorrentRasterbar_CUSTOM_BOOST_DEPENDENCIES)
list(SORT _boost_components)
message(STATUS "Libtorrent Boost dependencies: ${_boost_components}")
find_package(Boost REQUIRED COMPONENTS ${_boost_components})
set(LibtorrentRasterbar_LIBRARIES ${LibtorrentRasterbar_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
foreach(_boost_cmpnt IN LISTS _boost_components)
list(APPEND LibtorrentRasterbar_LIBRARIES "Boost::${_boost_cmpnt}")
endforeach(_boost_cmpnt)
set(LibtorrentRasterbar_INCLUDE_DIRS ${LibtorrentRasterbar_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
list(FIND LibtorrentRasterbar_DEFINITIONS -DTORRENT_USE_OPENSSL LibtorrentRasterbar_ENCRYPTION_INDEX)
if(LibtorrentRasterbar_ENCRYPTION_INDEX GREATER -1)
@@ -83,10 +108,7 @@ include(FindPackageHandleStandardArgs)
# if all listed variables are TRUE
find_package_handle_standard_args(LibtorrentRasterbar DEFAULT_MSG
LibtorrentRasterbar_LIBRARY
LibtorrentRasterbar_INCLUDE_DIR
Boost_SYSTEM_FOUND
Boost_CHRONO_FOUND
Boost_RANDOM_FOUND)
LibtorrentRasterbar_INCLUDE_DIR)
mark_as_advanced(LibtorrentRasterbar_INCLUDE_DIR LibtorrentRasterbar_LIBRARY
LibtorrentRasterbar_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES

View File

@@ -0,0 +1,28 @@
# function for parsing version variables that are set in version.pri file
# the version identifiers there are defined as follows:
# VER_MAJOR = 3
# VER_MINOR = 4
# VER_BUGFIX = 0
# VER_BUILD = 0
# VER_STATUS = alpha
function(read_version priFile outMajor outMinor outBugfix outBuild outStatus)
file(STRINGS ${priFile} _priFileContents REGEX "^VER_.+")
# message(STATUS "version.pri version contents: ${_priFileContents}")
# the _priFileContents variable contains something like the following:
# VER_MAJOR = 3;VER_MINOR = 4;VER_BUGFIX = 0;VER_BUILD = 0;VER_STATUS = alpha # Should be empty for stable releases!
set(_regex "VER_MAJOR += +([0-9]+);VER_MINOR += +([0-9]+);VER_BUGFIX += +([0-9]+);VER_BUILD += +([0-9]+);VER_STATUS += +([0-9A-Za-z]+)?")
# note quotes around _regex, they are needed because the variable contains semicolons
string(REGEX MATCH "${_regex}" _tmp "${_priFileContents}")
if (NOT _tmp)
message(FATAL_ERROR "Could not detect project version number from ${priFile}")
endif()
# message(STATUS "Matched version string: ${_tmp}")
set(${outMajor} ${CMAKE_MATCH_1} PARENT_SCOPE)
set(${outMinor} ${CMAKE_MATCH_2} PARENT_SCOPE)
set(${outBugfix} ${CMAKE_MATCH_3} PARENT_SCOPE)
set(${outBuild} ${CMAKE_MATCH_4} PARENT_SCOPE)
set(${outStatus} ${CMAKE_MATCH_5} PARENT_SCOPE)
endfunction()

View File

@@ -5,11 +5,23 @@
macro (target_link_qt_components target)
if (QT4_FOUND)
foreach(_cmp ${ARGN})
list(APPEND _QT_CMPNTS "Qt4::Qt${_cmp}")
if ("${_cmp}" STREQUAL "PRIVATE" OR
"${_cmp}" STREQUAL "PUBLIC" OR
"${_cmp}" STREQUAL "INTERFACE")
list(APPEND _QT_CMPNTS "${_cmp}")
else()
list(APPEND _QT_CMPNTS "Qt4::Qt${_cmp}")
endif()
endforeach()
else (QT4_FOUND)
foreach(_cmp ${ARGN})
list(APPEND _QT_CMPNTS "Qt5::${_cmp}")
if ("${_cmp}" STREQUAL "PRIVATE" OR
"${_cmp}" STREQUAL "PUBLIC" OR
"${_cmp}" STREQUAL "INTERFACE")
list(APPEND _QT_CMPNTS "${_cmp}")
else()
list(APPEND _QT_CMPNTS "Qt5::${_cmp}")
endif()
endforeach()
endif (QT4_FOUND)
target_link_libraries(${target} ${_QT_CMPNTS})

View File

@@ -9,7 +9,10 @@ set(LibtorrentRasterbar_CUSTOM_DEFINITIONS
-DBOOST_EXCEPTION_DISABLE
-DBOOST_SYSTEM_STATIC_LINK=1
-DTORRENT_USE_OPENSSL
-DUNICODE
-D__USE_W32_SOCKETS
-D_FILE_OFFSET_BITS=64)
add_definitions(-DUNICODE
-D_UNICODE
-DWIN32
-D_WIN32
@@ -18,9 +21,7 @@ set(LibtorrentRasterbar_CUSTOM_DEFINITIONS
-D_WIN32_IE=0x0500
-D_CRT_SECURE_NO_DEPRECATE
-D_SCL_SECURE_NO_DEPRECATE
-D__USE_W32_SOCKETS
-D_FILE_OFFSET_BITS=64)
)
# and boost
set(Boost_USE_STATIC_LIBS True)
# set(Boost_USE_STATIC_RUNTIME True)
@@ -29,16 +30,17 @@ set(Boost_USE_STATIC_LIBS True)
# with usual unix subdirectories (bin, lib, include)
# if so, we just need to set CMAKE_SYSTEM_PREFIX_PATH
# If it is not the case, individual paths need to be specified manually (see below)
set(COMMON_INSTALL_PREFIX "c:/usr")
set(COMMON_INSTALL_PREFIX "c:/usr" CACHE PATH "Prefix used to install all the required libraries")
list(APPEND CMAKE_SYSTEM_PREFIX_PATH "${COMMON_INSTALL_PREFIX}")
# If two version of Qt are installed, separate prefixes are needed most likely
set(QT4_INSTALL_PREFIX "${COMMON_INSTALL_PREFIX}/lib/qt4")
set(QT5_INSTALL_PREFIX "${COMMON_INSTALL_PREFIX}/lib/qt5")
set(QT4_INSTALL_PREFIX "${COMMON_INSTALL_PREFIX}/lib/qt4" CACHE PATH "Prefix where Qt4 is installed")
set(QT5_INSTALL_PREFIX "${COMMON_INSTALL_PREFIX}/lib/qt5" CACHE PATH "Prefix where Qt5 is installed")
# it is safe to set Qt dirs even if their files are directly in the prefix
# Qt4
if(NOT QT5)
# for qt 4 we need qmake, Qt5 provides cmake config files
LIST(APPEND CMAKE_PROGRAM_PATH "${QT4_INSTALL_PREFIX}/bin/")
endif(NOT QT5)

View File

@@ -9,6 +9,8 @@ QMAKE_CXXFLAGS += @QBT_CONF_EXTRA_CFLAGS@
EXTERNAL_INCLUDES = @QBT_CONF_INCLUDES@
EXTERNAL_INCLUDES -= $$QMAKE_DEFAULT_INCDIRS
# added /usr/local/include due to Qt 5.7.0 bug on macOS
macx: EXTERNAL_INCLUDES += "/usr/local/include"
INCLUDEPATH += $$EXTERNAL_INCLUDES
EXTERNAL_LIBS = @LDFLAGS@ @LIBS@

98
configure vendored
View File

@@ -4257,6 +4257,17 @@ else
$as_echo "no" >&6; }
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OS is macOS" >&5
$as_echo_n "checking whether OS is macOS... " >&6; }
if expr "$host_os" : ".*darwin.*" > /dev/null; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
enable_qt_dbus=no
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
# Require 0.23 pkg-config
@@ -4493,53 +4504,17 @@ fi
fi
as_ac_File=`$as_echo "ac_cv_file_$QT_QMAKE/qmake" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $QT_QMAKE/qmake" >&5
$as_echo_n "checking for $QT_QMAKE/qmake... " >&6; }
if eval \${$as_ac_File+:} false; then :
$as_echo_n "(cached) " >&6
else
test "$cross_compiling" = yes &&
as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
if test -r "$QT_QMAKE/qmake"; then
eval "$as_ac_File=yes"
else
eval "$as_ac_File=no"
fi
fi
eval ac_res=\$$as_ac_File
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
if eval test \"x\$"$as_ac_File"\" = x"yes"; then :
if test -f "$QT_QMAKE/qmake"; then :
QT_QMAKE="$QT_QMAKE/qmake"
else
as_ac_File=`$as_echo "ac_cv_file_$QT_QMAKE/qmake-qt5" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $QT_QMAKE/qmake-qt5" >&5
$as_echo_n "checking for $QT_QMAKE/qmake-qt5... " >&6; }
if eval \${$as_ac_File+:} false; then :
$as_echo_n "(cached) " >&6
else
test "$cross_compiling" = yes &&
as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
if test -r "$QT_QMAKE/qmake-qt5"; then
eval "$as_ac_File=yes"
else
eval "$as_ac_File=no"
fi
fi
eval ac_res=\$$as_ac_File
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
if eval test \"x\$"$as_ac_File"\" = x"yes"; then :
if test -f "$QT_QMAKE/qmake-qt5"; then :
QT_QMAKE="$QT_QMAKE/qmake-qt5"
else
QT_QMAKE=""
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Qt5 qmake >= 5.2.0" >&5
$as_echo_n "checking for Qt5 qmake >= 5.2.0... " >&6; }
if test "x$QT_QMAKE" != "x"; then :
@@ -4610,53 +4585,17 @@ fi
fi
as_ac_File=`$as_echo "ac_cv_file_$QT_QMAKE/qmake" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $QT_QMAKE/qmake" >&5
$as_echo_n "checking for $QT_QMAKE/qmake... " >&6; }
if eval \${$as_ac_File+:} false; then :
$as_echo_n "(cached) " >&6
else
test "$cross_compiling" = yes &&
as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
if test -r "$QT_QMAKE/qmake"; then
eval "$as_ac_File=yes"
else
eval "$as_ac_File=no"
fi
fi
eval ac_res=\$$as_ac_File
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
if eval test \"x\$"$as_ac_File"\" = x"yes"; then :
if test -f "$QT_QMAKE/qmake"; then :
QT_QMAKE="$QT_QMAKE/qmake"
else
as_ac_File=`$as_echo "ac_cv_file_$QT_QMAKE/qmake-qt4" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $QT_QMAKE/qmake-qt4" >&5
$as_echo_n "checking for $QT_QMAKE/qmake-qt4... " >&6; }
if eval \${$as_ac_File+:} false; then :
$as_echo_n "(cached) " >&6
else
test "$cross_compiling" = yes &&
as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
if test -r "$QT_QMAKE/qmake-qt4"; then
eval "$as_ac_File=yes"
else
eval "$as_ac_File=no"
fi
fi
eval ac_res=\$$as_ac_File
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
if eval test \"x\$"$as_ac_File"\" = x"yes"; then :
if test -f "$QT_QMAKE/qmake-qt4"; then :
QT_QMAKE="$QT_QMAKE/qmake-qt4"
else
QT_QMAKE=""
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Qt4 qmake >= 4.8.0" >&5
$as_echo_n "checking for Qt4 qmake >= 4.8.0... " >&6; }
if test "x$QT_QMAKE" != "x"; then :
@@ -5033,8 +4972,8 @@ fi
if test "x$BOOST_CPPFLAGS" = "x"; then :
as_fn_error $? "Could not find Boost" "$LINENO" 5
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: Boost CPPFLGAS: $BOOST_CPPFLAGS" >&5
$as_echo "$as_me: Boost CPPFLGAS: $BOOST_CPPFLAGS" >&6;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: Boost CPPFLAGS: $BOOST_CPPFLAGS" >&5
$as_echo "$as_me: Boost CPPFLAGS: $BOOST_CPPFLAGS" >&6;}
CPPFLAGS="$BOOST_CPPFLAGS $CPPFLAGS"
LDFLAGS="$BOOST_LDFLAGS $LDFLAGS"
fi
@@ -5083,6 +5022,7 @@ ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ex
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
CXXFLAGS_SAVE=$CXXFLAGS
CXXFLAGS=
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -5090,7 +5030,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
int
main ()
{
boost::system::system_category
boost::system::error_category *a = 0;
;
return 0;
}

View File

@@ -67,6 +67,12 @@ AS_IF([expr "$host_os" : ".*freebsd.*" > /dev/null],
LIBS="-lexecinfo $LIBS"],
[AC_MSG_RESULT([no])])
AC_MSG_CHECKING([whether OS is macOS])
AS_IF([expr "$host_os" : ".*darwin.*" > /dev/null],
[AC_MSG_RESULT([yes])
enable_qt_dbus=no],
[AC_MSG_RESULT([no])])
# Require 0.23 pkg-config
PKG_PROG_PKG_CONFIG([0.23])
AS_IF([test "x$PKG_CONFIG" = "x"],
@@ -156,7 +162,7 @@ AX_BOOST_BASE([1.35])
# how to test for a set vs unset variable.
AS_IF([test "x$BOOST_CPPFLAGS" = "x"],
[AC_MSG_ERROR([Could not find Boost])],
[AC_MSG_NOTICE([Boost CPPFLGAS: $BOOST_CPPFLAGS])
[AC_MSG_NOTICE([Boost CPPFLAGS: $BOOST_CPPFLAGS])
CPPFLAGS="$BOOST_CPPFLAGS $CPPFLAGS"
LDFLAGS="$BOOST_LDFLAGS $LDFLAGS"])

8
dist/mac/Info.plist vendored
View File

@@ -37,7 +37,7 @@
</dict>
</array>
<key>CFBundleName</key>
<string>qBittorrent</string>
<string>@EXECUTABLE@</string>
<key>CFBundleIconFile</key>
<string>qbittorrent_mac.icns</string>
<key>CFBundleInfoDictionaryVersion</key>
@@ -45,11 +45,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>3.3.7</string>
<string>3.3.11</string>
<key>CFBundleSignature</key>
<string>qBit</string>
<key>CFBundleExecutable</key>
<string>qbittorrent</string>
<string>@EXECUTABLE@</string>
<key>CFBundleIdentifier</key>
<string>org.qbittorrent</string>
<key>NSPrincipalClass</key>
@@ -59,7 +59,7 @@
<key>NSAppleScriptEnabled</key>
<string>YES</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2006-2016 The qBittorrent project</string>
<string>Copyright © 2006-2017 The qBittorrent project</string>
<key>UTExportedTypeDeclarations</key>
<array>
<dict>

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 893 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -1,12 +1,12 @@
TRANSLATORS:
1. Use an editor that has NSIS syntax highlighting(eg Notepad++/Geany). This will
1. Use an editor that has NSIS syntax highlighting(eg Notepad++/Geany). This will
make your life easier.
2. Open the relevant .nsi file that exists in the folder named
2. Open the relevant .nsi file that exists in the folder named
"installer-translations"
3. Lines starting with ";" are considered comments. These include the
3. Lines starting with ";" are considered comments. These include the
english message to help you with the translation.
4. Edit only the part inside the quotation marks(""). Unless you know
4. Edit only the part inside the quotation marks(""). Unless you know
what you are doing.
5. Save the files with utf8 encoding and BOM.
6. Submit your changes: 1) as a pull request to the official git repo or
@@ -16,17 +16,13 @@ TRANSLATORS:
PACKAGERS:
You will need NSIS and upx to make the installer. You need a unicode version of NSIS.
I tested with NSIS 3.0a0.
I tested with NSIS 3.0 (final).
1. Open the options.nsi file in an editor and change line that contains
"!define PROG_VERSION "3.0.3"" to the version of qbittorrent you just built.
2. Extract the plugins found in the folder "nsis plugins" into your
"!define PROG_VERSION "3.0.3"" to the version of qbittorrent you just built.
2. Extract the plugins found in the folder "nsis plugins" into your
NSIS's unicode Plugin directory(usually C:\Program Files\NSIS\Plugins\x86-unicode).
Only the *.dll files are needed. Don't use the .dll from UAC.zip, use the one from "UAC Unicode.zip".
NOTE: To build the unicode version of UAC with MSVC2008 you need:
a) the sources from UAC.zip
b) apply the util.cpp.diff from "UAC Unicode.zip" to util.cpp
c) in a msvc command prompt issue: cl.exe /O1s /GS- /GR- /EHs-c- /Zl /LD /DUNICODE RunAs.cpp uac.cpp util.cpp /link kernel32.lib user32.lib shell32.lib advapi32.lib ole32.lib /DLL /MANIFEST:NO /OUT:uac.dll
Only the *.dll files are needed. Use the unicode version of the dlls.
3. The script you need to compile is "qbittorrent.nsi". It includes all other necessary scripts.
4. The script expects the following file tree:
@@ -53,10 +49,11 @@ qbittorrent.exe
qbittorrent.nsi
qt.conf
translations.nsi
UAC.nsh
uninstaller.nsi
5. "license.txt" is a text file that contains the text rendered
5. "license.txt" is a text file that contains the text rendered
from src\gui\gpl.html or the text contained in COPYING
6. "qbittorrent.exe" is the compiled binary file.
@@ -64,7 +61,7 @@ SCRIPT HACKERS:
If you add any new LangString variable to the scripts you NEED to provide
"translations" of it to all the .nsi files inside "installer-translations.
You can always leave the english string but you have to use all the LANG_<lang name>
for the given variable. Otherwise, if the user chooses a language that you
haven't provided a LANG_<lang name> for your variable then your string will be empty.
You can always leave the english string but you have to use all the LANG_<lang name>
for the given variable. Otherwise, if the user chooses a language that you
haven't provided a LANG_<lang name> for your variable then your string will be empty.
Don't worry though, NSIS throws warnings for this when compiling the scripts.

View File

@@ -228,6 +228,8 @@ pop $_LOGICLIB_TEMP
!undef _UAC_ParseDefineFlags_orin_this
!ifdef _UAC_ParseDefineFlags_orin_f1
!undef _UAC_ParseDefineFlags_orin_f1
!endif
!ifdef _UAC_ParseDefineFlags_orin_f2
!undef _UAC_ParseDefineFlags_orin_f2
!endif
!macroend

View File

@@ -17,7 +17,7 @@ LangString inst_firewallinfo ${LANG_PORTUGUESE} "Adicionando regra à firewall d
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
LangString inst_warning ${LANG_PORTUGUESE} "O qBittorrent está a ser executado. Feche a aplicação antes de instalar esta versão."
;LangString inst_uninstall_question ${LANG_ENGLISH} "A previous installation was detected. It will be uninstalled without deleting user settings."
LangString inst_uninstall_question ${LANG_PORTUGUESE} "A previous installation was detected. It will be uninstalled without deleting user settings."
LangString inst_uninstall_question ${LANG_PORTUGUESE} "Uma antiga instalação foi encontrada.Essa mesma será desinstalada sem apagar as definições do usuário."
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
LangString inst_unist ${LANG_PORTUGUESE} "A desinstalar versão anterior."
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."

View File

@@ -17,7 +17,7 @@ LangString inst_firewallinfo ${LANG_PORTUGUESEBR} "Adicionando regra no firewall
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
LangString inst_warning ${LANG_PORTUGUESEBR} "qBittorrent está rodando. Por favor feche a aplicação antes de instalar."
;LangString inst_uninstall_question ${LANG_ENGLISH} "A previous installation was detected. It will be uninstalled without deleting user settings."
LangString inst_uninstall_question ${LANG_PORTUGUESEBR} "A previous installation was detected. It will be uninstalled without deleting user settings."
LangString inst_uninstall_question ${LANG_PORTUGUESEBR} "Uma instalação anterior foi detectada. Ela será desistalada sem deletar as configurações de usuário."
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
LangString inst_unist ${LANG_PORTUGUESEBR} "Desinstalando versão anterior."
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."

View File

@@ -1,51 +1,51 @@
;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_TURKISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_TURKISH} "qBittorrent (zorunlu)"
;LangString inst_dekstop ${LANG_ENGLISH} "Create Desktop Shortcut"
LangString inst_dekstop ${LANG_TURKISH} "Create Desktop Shortcut"
LangString inst_dekstop ${LANG_TURKISH} "Masaüstü Kısayolu oluştur"
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
LangString inst_startmenu ${LANG_TURKISH} "Create Start Menu Shortcut"
LangString inst_startmenu ${LANG_TURKISH} "Başlangıç Menüsü Kısayolu oluştur"
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
LangString inst_torrent ${LANG_TURKISH} "Open .torrent files with qBittorrent"
LangString inst_torrent ${LANG_TURKISH} ".torrent dosyalarını qBittorrent ile aç"
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
LangString inst_magnet ${LANG_TURKISH} "Open magnet links with qBittorrent"
LangString inst_magnet ${LANG_TURKISH} "Magnet bağlantılarını qBittorrent ile aç"
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
LangString inst_firewall ${LANG_TURKISH} "Add Windows Firewall rule"
LangString inst_firewall ${LANG_TURKISH} "Windows Güvenlik Duvarı kuralı ekle"
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
LangString inst_firewallinfo ${LANG_TURKISH} "Adding Windows Firewall rule"
LangString inst_firewallinfo ${LANG_TURKISH} "Windows Güvenlik Duvarı kuralı ekleniyor"
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
LangString inst_warning ${LANG_TURKISH} "qBittorrent is running. Please close the application before installing."
LangString inst_warning ${LANG_TURKISH} "qBittorrent çalışıyor. Lütfen yüklemeden önce uygulamayı kapatın."
;LangString inst_uninstall_question ${LANG_ENGLISH} "A previous installation was detected. It will be uninstalled without deleting user settings."
LangString inst_uninstall_question ${LANG_TURKISH} "A previous installation was detected. It will be uninstalled without deleting user settings."
LangString inst_uninstall_question ${LANG_TURKISH} "Önceki bir kurulum algılandı. Kullanıcı ayarları silinmeden kaldırılacaktır."
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
LangString inst_unist ${LANG_TURKISH} "Uninstalling previous version."
LangString inst_unist ${LANG_TURKISH} "Önceki sürüm kaldırılıyor."
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
LangString launch_qbt ${LANG_TURKISH} "Launch qBittorrent."
LangString launch_qbt ${LANG_TURKISH} "qBittorrent'i çalıştır."
;------------------------------------
;Uninstaller strings
;LangString remove_files ${LANG_ENGLISH} "Remove files"
LangString remove_files ${LANG_TURKISH} "Remove files"
LangString remove_files ${LANG_TURKISH} "Dosyaları kaldır"
;LangString remove_shortcuts ${LANG_ENGLISH} "Remove shortcuts"
LangString remove_shortcuts ${LANG_TURKISH} "Remove shortcuts"
LangString remove_shortcuts ${LANG_TURKISH} "Kısayolları kaldır"
;LangString remove_associations ${LANG_ENGLISH} "Remove file associations"
LangString remove_associations ${LANG_TURKISH} "Remove file associations"
LangString remove_associations ${LANG_TURKISH} "Dosya ilişkilendirmelerini kaldır"
;LangString remove_registry ${LANG_ENGLISH} "Remove registry keys"
LangString remove_registry ${LANG_TURKISH} "Remove registry keys"
LangString remove_registry ${LANG_TURKISH} "Kayıt defteri anahtarlarını kaldır"
;LangString remove_conf ${LANG_ENGLISH} "Remove configuration files"
LangString remove_conf ${LANG_TURKISH} "Remove configuration files"
LangString remove_conf ${LANG_TURKISH} "Yapılandırma dosyalarını kaldır"
;LangString remove_firewall ${LANG_ENGLISH} "Remove Windows Firewall rule"
LangString remove_firewall ${LANG_TURKISH} "Remove Windows Firewall rule"
LangString remove_firewall ${LANG_TURKISH} "Windows Güvenlik Duvarı kuralını kaldır"
;LangString remove_firewallinfo ${LANG_ENGLISH} "Removing Windows Firewall rule"
LangString remove_firewallinfo ${LANG_TURKISH} "Removing Windows Firewall rule"
LangString remove_firewallinfo ${LANG_TURKISH} "Windows Güvenlik Duvarı kuralı kaldırılıyor"
;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data"
LangString remove_cache ${LANG_TURKISH} "Remove torrents and cached data"
LangString remove_cache ${LANG_TURKISH} "Torrentleri ve önbelleklenen verileri kaldır"
;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling."
LangString uninst_warning ${LANG_TURKISH} "qBittorrent is running. Please close the application before uninstalling."
LangString uninst_warning ${LANG_TURKISH} "qBittorrent çalışıyor. Lütfen kaldırmadan önce uygulamayı kapatın."
;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:"
LangString uninst_tor_warn ${LANG_TURKISH} "Not removing .torrent association. It is associated with:"
LangString uninst_tor_warn ${LANG_TURKISH} ".torrent ilişkilendirmesi kaldırılmıyor. Şununla ilişkilendirildi:"
;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:"
LangString uninst_mag_warn ${LANG_TURKISH} "Not removing magnet association. It is associated with:"
LangString uninst_mag_warn ${LANG_TURKISH} "Magnet ilişkilendirmesi kaldırılmıyor. Şununla ilişkilendirildi:"

Binary file not shown.

Binary file not shown.

View File

@@ -19,7 +19,7 @@ XPStyle on
!define CSIDL_APPDATA '0x1A' ;Application Data path
!define CSIDL_LOCALAPPDATA '0x1C' ;Local Application Data path
!define PROG_VERSION "3.3.7"
!define PROG_VERSION "3.3.11"
!define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun
!define MUI_FINISHPAGE_RUN_TEXT $(launch_qbt)
@@ -33,7 +33,7 @@ OutFile "qbittorrent_${PROG_VERSION}_setup.exe"
;Installer Version Information
VIAddVersionKey "ProductName" "qBittorrent"
VIAddVersionKey "CompanyName" "The qBittorrent project"
VIAddVersionKey "LegalCopyright" "Copyright ©2006-2016 The qBittorrent project"
VIAddVersionKey "LegalCopyright" "Copyright ©2006-2017 The qBittorrent project"
VIAddVersionKey "FileDescription" "qBittorrent - A Bittorrent Client"
VIAddVersionKey "FileVersion" "${PROG_VERSION}"

View File

@@ -31,7 +31,7 @@
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 17
#serial 18
AC_DEFUN([AX_BOOST_SYSTEM],
[
@@ -68,9 +68,10 @@ AC_DEFUN([AX_BOOST_SYSTEM],
ax_cv_boost_system,
[AC_LANG_PUSH([C++])
CXXFLAGS_SAVE=$CXXFLAGS
CXXFLAGS=
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/system/error_code.hpp>]],
[[boost::system::system_category]])],
[[boost::system::error_category *a = 0;]])],
ax_cv_boost_system=yes, ax_cv_boost_system=no)
CXXFLAGS=$CXXFLAGS_SAVE
AC_LANG_POP([C++])

View File

@@ -12,9 +12,9 @@ AC_DEFUN([FIND_QT4],
[QT_QMAKE=`AS_DIRNAME(["$QT_QMAKE"])`])
])
AC_CHECK_FILE([$QT_QMAKE/qmake],
AS_IF([test -f "$QT_QMAKE/qmake"],
[QT_QMAKE="$QT_QMAKE/qmake"],
[AC_CHECK_FILE([$QT_QMAKE/qmake-qt4],
[AS_IF([test -f "$QT_QMAKE/qmake-qt4"],
[QT_QMAKE="$QT_QMAKE/qmake-qt4"],
[QT_QMAKE=""])
])
@@ -36,9 +36,9 @@ AC_DEFUN([FIND_QT5],
[host_bins])
])
AC_CHECK_FILE([$QT_QMAKE/qmake],
AS_IF([test -f "$QT_QMAKE/qmake"],
[QT_QMAKE="$QT_QMAKE/qmake"],
[AC_CHECK_FILE([$QT_QMAKE/qmake-qt5],
[AS_IF([test -f "$QT_QMAKE/qmake-qt5"],
[QT_QMAKE="$QT_QMAKE/qmake-qt5"],
[QT_QMAKE=""])
])

View File

@@ -161,10 +161,15 @@ endif (GUI AND WIN32)
target_link_libraries(${QBT_TARGET_NAME} ${QBT_TARGET_LIBRARIES} QtSingleApplication::QtSingleApplication)
if (APPLE)
set(qbt_BUNDLE_NAME "${CMAKE_PROJECT_NAME}")
set(qbt_BUNDLE_NAME "${QBT_TARGET_NAME}")
# substitute @EXECUTABLE@ in dist/mac/Info.plist
set(EXECUTABLE ${qbt_BUNDLE_NAME})
configure_file(${qBittorrent_SOURCE_DIR}/dist/mac/Info.plist ${qBittorrent_BINARY_DIR}/dist/mac/Info.plist @ONLY)
set_target_properties(${QBT_TARGET_NAME} PROPERTIES
MACOSX_BUNDLE_BUNDLE_NAME "${qbt_BUNDLE_NAME}"
MACOSX_BUNDLE_INFO_PLIST ${qBittorrent_SOURCE_DIR}/dist/mac/Info.plist
MACOSX_BUNDLE_INFO_PLIST ${qBittorrent_BINARY_DIR}/dist/mac/Info.plist
)
endif (APPLE)

View File

@@ -70,6 +70,7 @@
#include "base/net/smtp.h"
#include "base/net/downloadmanager.h"
#include "base/net/geoipmanager.h"
#include "base/net/proxyconfigurationmanager.h"
#include "base/bittorrent/session.h"
#include "base/bittorrent/torrenthandle.h"
@@ -263,7 +264,7 @@ void Application::runExternalProgram(BitTorrent::TorrentHandle *const torrent) c
#elif defined(Q_OS_WIN) // test cmd: `echo "%F" > "c:\ab ba.txt"`
program.prepend(QLatin1String("\"")).append(QLatin1String("\""));
program.prepend(Utils::Misc::windowsSystemPath() + QLatin1String("\\cmd.exe /C "));
const uint cmdMaxLength = 32768; // max length (incl. terminate char) for `lpCommandLine` in `CreateProcessW()`
const int cmdMaxLength = 32768; // max length (incl. terminate char) for `lpCommandLine` in `CreateProcessW()`
if ((program.size() + 1) > cmdMaxLength) {
logger->addMessage(tr("Torrent: %1, run external program command too long (length > %2), execution failed.").arg(torrent->name()).arg(cmdMaxLength), Log::CRITICAL);
return;
@@ -395,6 +396,7 @@ void Application::processParams(const QStringList &params)
int Application::exec(const QStringList &params)
{
Net::ProxyConfigurationManager::initInstance();
Net::DownloadManager::initInstance();
#ifdef DISABLE_GUI
IconProvider::initInstance();
@@ -509,36 +511,27 @@ void Application::initializeTranslation()
{
Preferences* const pref = Preferences::instance();
// Load translation
QString locale = pref->getLocale();
QString localeStr = pref->getLocale();
QLocale::setDefault(QLocale(localeStr));
if (locale.isEmpty()) {
locale = QLocale::system().name();
pref->setLocale(locale);
}
if (m_qtTranslator.load(
if (
#ifdef QBT_USES_QT5
QString::fromUtf8("qtbase_") + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath)) ||
m_qtTranslator.load(
m_qtTranslator.load(QString::fromUtf8("qtbase_") + localeStr, QLibraryInfo::location(QLibraryInfo::TranslationsPath)) ||
#endif
QString::fromUtf8("qt_") + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
qDebug("Qt %s locale recognized, using translation.", qPrintable(locale));
}
else {
qDebug("Qt %s locale unrecognized, using default (en).", qPrintable(locale));
}
m_qtTranslator.load(QString::fromUtf8("qt_") + localeStr, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
qDebug("Qt %s locale recognized, using translation.", qPrintable(localeStr));
else
qDebug("Qt %s locale unrecognized, using default (en).", qPrintable(localeStr));
installTranslator(&m_qtTranslator);
if (m_translator.load(QString::fromUtf8(":/lang/qbittorrent_") + locale)) {
qDebug("%s locale recognized, using translation.", qPrintable(locale));
}
else {
qDebug("%s locale unrecognized, using default (en).", qPrintable(locale));
}
if (m_translator.load(QString::fromUtf8(":/lang/qbittorrent_") + localeStr))
qDebug("%s locale recognized, using translation.", qPrintable(localeStr));
else
qDebug("%s locale unrecognized, using default (en).", qPrintable(localeStr));
installTranslator(&m_translator);
#ifndef DISABLE_GUI
if (locale.startsWith("ar") || locale.startsWith("he")) {
if (localeStr.startsWith("ar") || localeStr.startsWith("he")) {
qDebug("Right to Left mode");
setLayoutDirection(Qt::RightToLeft);
}
@@ -621,11 +614,13 @@ void Application::cleanup()
Net::GeoIPManager::freeInstance();
#endif
Net::DownloadManager::freeInstance();
Net::ProxyConfigurationManager::freeInstance();
Preferences::freeInstance();
SettingsStorage::freeInstance();
delete m_fileLogger;
Logger::freeInstance();
IconProvider::freeInstance();
Utils::Fs::removeDirRecursive(Utils::Fs::tempPath());
#ifndef DISABLE_GUI
#ifdef Q_OS_WIN

View File

@@ -135,6 +135,16 @@ int main(int argc, char *argv[])
// We must save it here because QApplication constructor may change it
bool isOneArg = (argc == 2);
#ifdef Q_OS_MAC
// On macOS 10.12 Sierra, Apple changed the behaviour of CFPreferencesSetValue() https://bugreports.qt.io/browse/QTBUG-56344
// Due to this, we have to move from native plist to IniFormat
macMigratePlists();
#endif
#ifndef DISABLE_GUI
migrateRSS();
#endif
// Create Application
QString appId = QLatin1String("qBittorrent-") + Utils::Misc::getUserIDString();
QScopedPointer<Application> app(new Application(appId, argc, argv));
@@ -230,6 +240,17 @@ int main(int argc, char *argv[])
qputenv("QT_BEARER_POLL_TIMEOUT", QByteArray::number(-1));
#endif
#if defined(Q_OS_MAC)
{
// Since Apple made difficult for users to set PATH, we set here for convenience.
// Users are supposed to install Homebrew Python for search function.
// For more info see issue #5571.
QByteArray path = "/usr/local/bin:";
path += qgetenv("PATH");
qputenv("PATH", path.constData());
}
#endif
#ifndef DISABLE_GUI
if (!upgrade()) return EXIT_FAILURE;
#else

View File

@@ -15,78 +15,86 @@ static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames
fprintf(out, "stack trace:\n");
// storage array for stack trace address data
void* addrlist[max_frames+1];
void *addrlist[max_frames + 1];
// retrieve current stack addresses
int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));
int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void *));
if (addrlen == 0) {
fprintf(out, " <empty, possibly corrupt>\n");
return;
fprintf(out, " <empty, possibly corrupt>\n");
return;
}
// resolve addresses into strings containing "filename(function+address)",
// this array must be free()-ed
char** symbollist = backtrace_symbols(addrlist, addrlen);
char * *symbollist = backtrace_symbols(addrlist, addrlen);
// allocate string which will be filled with the demangled function name
size_t funcnamesize = 256;
char* funcname = (char*)malloc(funcnamesize);
char *funcname = (char *)malloc(funcnamesize);
int functionNamesFound = 0;
// iterate over the returned symbol lines. skip the first, it is the
// address of this function.
for (int i = 2; i < addrlen; i++)
{
char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
for (int i = 2; i < addrlen; i++) {
char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
// find parentheses and +address offset surrounding the mangled name:
// ./module(function+0x15c) [0x8048a6d]
//fprintf(out, "%s TT\n", symbollist[i]);
for (char *p = symbollist[i]; *p; ++p)
{
if (*p == '(')
begin_name = p;
else if (*p == '+')
begin_offset = p;
else if (*p == ')' && begin_offset) {
end_offset = p;
break;
}
}
// find parentheses and +address offset surrounding the mangled name:
// ./module(function+0x15c) [0x8048a6d]
// fprintf(out, "%s TT\n", symbollist[i]);
for (char *p = symbollist[i]; *p; ++p) {
if (*p == '(') {
begin_name = p;
}
else if (*p == '+') {
begin_offset = p;
}
else if ((*p == ')') && begin_offset) {
end_offset = p;
break;
}
}
if (begin_name && begin_offset && end_offset
&& begin_name < begin_offset)
{
*begin_name++ = '\0';
*begin_offset++ = '\0';
*end_offset = '\0';
if (begin_name && begin_offset && end_offset
&& (begin_name < begin_offset)) {
*begin_name++ = '\0';
*begin_offset++ = '\0';
*end_offset = '\0';
// mangled name is now in [begin_name, begin_offset) and caller
// offset in [begin_offset, end_offset). now apply
// __cxa_demangle():
// mangled name is now in [begin_name, begin_offset) and caller
// offset in [begin_offset, end_offset). now apply
// __cxa_demangle():
int status;
char* ret = abi::__cxa_demangle(begin_name,
funcname, &funcnamesize, &status);
if (status == 0) {
funcname = ret; // use possibly realloc()-ed string
fprintf(out, " %s : %s+%s %s\n",
symbollist[i], funcname, begin_offset, ++end_offset);
}
else {
// demangling failed. Output function name as a C function with
// no arguments.
fprintf(out, " %s : %s()+%s %s\n",
symbollist[i], begin_name, begin_offset, ++end_offset);
}
}
else
{
// couldn't parse the line? print the whole line.
fprintf(out, " %s\n", symbollist[i]);
}
int status;
char *ret = abi::__cxa_demangle(begin_name,
funcname, &funcnamesize, &status);
if (status == 0) {
funcname = ret; // use possibly realloc()-ed string
fprintf(out, " %s : %s+%s %s\n",
symbollist[i], funcname, begin_offset, ++end_offset);
}
else {
// demangling failed. Output function name as a C function with
// no arguments.
fprintf(out, " %s : %s()+%s %s\n",
symbollist[i], begin_name, begin_offset, ++end_offset);
}
++functionNamesFound;
}
else {
// couldn't parse the line? print the whole line.
fprintf(out, " %s\n", symbollist[i]);
}
}
if (!functionNamesFound) {
fprintf(out, "There were no function names found in the stack trace\n."
"Seems like debug symbols are not installed, and the stack trace is useless.\n");
}
if (functionNamesFound < addrlen - 2) {
fprintf(out, "Consider installing debug symbols for packages containing files with empty"
" function names (i.e. empty braces \"()\") to make your stack trace more useful\n");
}
free(funcname);
free(symbollist);
}

View File

@@ -29,24 +29,31 @@
#ifndef UPGRADE_H
#define UPGRADE_H
#include <libtorrent/lazy_entry.hpp>
#include <libtorrent/entry.hpp>
#include <libtorrent/version.hpp>
#if LIBTORRENT_VERSION_NUM >= 10100
#include <libtorrent/bdecode.hpp>
#endif
#include <libtorrent/bencode.hpp>
#include <libtorrent/entry.hpp>
#if LIBTORRENT_VERSION_NUM < 10100
#include <libtorrent/lazy_entry.hpp>
#endif
#include <QString>
#include <QDir>
#include <QFile>
#include <QRegExp>
#ifndef DISABLE_GUI
#include <QMessageBox>
#endif
#include <QRegExp>
#include <QString>
#include "base/logger.h"
#include "base/utils/fs.h"
#include "base/utils/misc.h"
#include "base/utils/string.h"
#include "base/qinisettings.h"
#include "base/preferences.h"
#include "base/qinisettings.h"
bool userAcceptsUpgrade()
{
@@ -86,10 +93,16 @@ bool upgradeResumeFile(const QString &filepath, const QVariantHash &oldTorrent =
QByteArray data = file1.readAll();
file1.close();
libtorrent::lazy_entry fastOld;
libtorrent::error_code ec;
libtorrent::lazy_bdecode(data.constData(), data.constData() + data.size(), fastOld, ec);
if (ec || (fastOld.type() != libtorrent::lazy_entry::dict_t)) return false;
#if LIBTORRENT_VERSION_NUM < 10100
libtorrent::lazy_entry fastOld;
libtorrent::lazy_bdecode(data.constData(), data.constData() + data.size(), fastOld, ec);
if (ec || (fastOld.type() != libtorrent::lazy_entry::dict_t)) return false;
#else
libtorrent::bdecode_node fastOld;
libtorrent::bdecode(data.constData(), data.constData() + data.size(), fastOld, ec);
if (ec || (fastOld.type() != libtorrent::bdecode_node::dict_t)) return false;
#endif
libtorrent::entry fastNew;
fastNew = fastOld;
@@ -143,7 +156,12 @@ bool upgrade(bool ask = true)
upgradeResumeFile(backupFolderDir.absoluteFilePath(backupFile));
// ****************************************************************************************
#ifdef Q_OS_MAC
// native .plist
QSettings *oldResumeSettings = new QSettings("qBittorrent", "qBittorrent-resume");
#else
QIniSettings *oldResumeSettings = new QIniSettings("qBittorrent", "qBittorrent-resume");
#endif
QString oldResumeFilename = oldResumeSettings->fileName();
QVariantHash oldResumeData = oldResumeSettings->value("torrents").toHash();
delete oldResumeSettings;
@@ -210,4 +228,50 @@ bool upgrade(bool ask = true)
return true;
}
#ifdef Q_OS_MAC
void migratePlistToIni(const QString &application)
{
QIniSettings iniFile("qBittorrent", application);
if (!iniFile.allKeys().isEmpty()) return; // We copy the contents of plist, only if inifile does not exist(is empty).
QSettings *plistFile = new QSettings("qBittorrent", application);
plistFile->setFallbacksEnabled(false);
const QStringList plist = plistFile->allKeys();
if (!plist.isEmpty()) {
foreach (const QString &key, plist)
iniFile.setValue(key, plistFile->value(key));
plistFile->clear();
}
QString plistPath = plistFile->fileName();
delete plistFile;
Utils::Fs::forceRemove(plistPath);
}
void macMigratePlists()
{
migratePlistToIni("qBittorrent-data");
migratePlistToIni("qBittorrent-rss");
migratePlistToIni("qBittorrent");
}
#endif // Q_OS_MAC
#ifndef DISABLE_GUI
void migrateRSS()
{
// Copy old feed items to new file if needed
QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss-feeds");
if (!qBTRSS.allKeys().isEmpty()) return; // We move the contents of RSS old_items only if inifile does not exist (is empty).
QIniSettings qBTRSSLegacy("qBittorrent", "qBittorrent-rss");
QHash<QString, QVariant> allOldItems = qBTRSSLegacy.value("old_items", QHash<QString, QVariant>()).toHash();
if (!allOldItems.empty()) {
qDebug("Moving %d old items for feeds to qBittorrent-rss-feeds", allOldItems.size());
qBTRSS.setValue("old_items", allOldItems);
qBTRSSLegacy.remove("old_items");
}
}
#endif
#endif // UPGRADE_H

View File

@@ -30,6 +30,7 @@ net/downloadmanager.h
net/geoipmanager.h
net/portforwarder.h
net/private/geoipdatabase.h
net/proxyconfigurationmanager.h
net/reverseresolution.h
net/smtp.h
rss/private/rssparser.h
@@ -88,6 +89,7 @@ net/downloadmanager.cpp
net/geoipmanager.cpp
net/portforwarder.cpp
net/private/geoipdatabase.cpp
net/proxyconfigurationmanager.cpp
net/reverseresolution.cpp
net/smtp.cpp
rss/private/rssparser.cpp
@@ -115,24 +117,24 @@ tristatebool.cpp
)
add_library(qbt_base STATIC ${QBT_BASE_HEADERS} ${QBT_BASE_SOURCES})
target_link_libraries(qbt_base ZLIB::ZLIB LibtorrentRasterbar::LibTorrent)
target_link_qt_components(qbt_base Core Network Xml)
target_link_libraries(qbt_base PRIVATE ZLIB::ZLIB PUBLIC LibtorrentRasterbar::LibTorrent)
target_link_qt_components(qbt_base PUBLIC Core Network Xml)
if (QT4_FOUND)
if (GUI)
target_link_libraries(qbt_base Qt4::QtGui)
target_link_libraries(qbt_base PUBLIC Qt4::QtGui)
endif (GUI)
else (QT4_FOUND)
if (GUI)
target_link_libraries(qbt_base Qt5::Gui Qt5::Widgets)
target_link_libraries(qbt_base PUBLIC Qt5::Gui Qt5::Widgets)
endif (GUI)
endif (QT4_FOUND)
if (DBUS)
target_link_qt_components(qbt_base DBus)
target_link_qt_components(qbt_base PRIVATE DBus)
endif ()
if (APPLE)
find_library(IOKit_LIBRARY IOKit)
find_library(Carbon_LIBRARY Carbon)
target_link_libraries(qbt_base ${Carbon_LIBRARY} ${IOKit_LIBRARY})
target_link_libraries(qbt_base PRIVATE ${Carbon_LIBRARY} ${IOKit_LIBRARY})
endif (APPLE)

View File

@@ -5,6 +5,7 @@ HEADERS += \
$$PWD/qinisettings.h \
$$PWD/logger.h \
$$PWD/settingsstorage.h \
$$PWD/settingvalue.h \
$$PWD/preferences.h \
$$PWD/indexrange.h \
$$PWD/iconprovider.h \
@@ -20,6 +21,7 @@ HEADERS += \
$$PWD/net/downloadhandler.h \
$$PWD/net/geoipmanager.h \
$$PWD/net/portforwarder.h \
$$PWD/net/proxyconfigurationmanager.h \
$$PWD/net/reverseresolution.h \
$$PWD/net/smtp.h \
$$PWD/net/private/geoipdatabase.h \
@@ -74,6 +76,7 @@ SOURCES += \
$$PWD/net/downloadhandler.cpp \
$$PWD/net/geoipmanager.cpp \
$$PWD/net/portforwarder.cpp \
$$PWD/net/proxyconfigurationmanager.cpp \
$$PWD/net/reverseresolution.cpp \
$$PWD/net/smtp.cpp \
$$PWD/net/private/geoipdatabase.cpp \

View File

@@ -31,13 +31,13 @@
#include <QTime>
#include <QDateTime>
#include "base/bittorrent/session.h"
#include "base/preferences.h"
#include "bandwidthscheduler.h"
BandwidthScheduler::BandwidthScheduler(QObject *parent)
: QTimer(parent)
{
Q_ASSERT(Preferences::instance()->isSchedulerEnabled());
// Single shot, we call start() again manually
setSingleShot(true);
// Connect Signals/Slots
@@ -47,8 +47,7 @@ BandwidthScheduler::BandwidthScheduler(QObject *parent)
void BandwidthScheduler::start()
{
const Preferences* const pref = Preferences::instance();
Q_ASSERT(pref->isSchedulerEnabled());
bool alt_bw_enabled = pref->isAltBandwidthEnabled();
bool alt_bw_enabled = BitTorrent::Session::instance()->isAltGlobalSpeedLimitEnabled();
QTime start = pref->getSchedulerStartTime();
QTime end = pref->getSchedulerEndTime();

View File

@@ -55,10 +55,10 @@ FilterParserThread::~FilterParserThread()
}
// Parser for eMule ip filter in DAT format
int FilterParserThread::parseDATFilterFile(QString m_filePath, libt::ip_filter &filter)
int FilterParserThread::parseDATFilterFile(QString filePath, libt::ip_filter &filter)
{
int ruleCount = 0;
QFile file(m_filePath);
QFile file(filePath);
if (!file.exists()) return ruleCount;
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
@@ -149,10 +149,10 @@ int FilterParserThread::parseDATFilterFile(QString m_filePath, libt::ip_filter &
}
// Parser for PeerGuardian ip filter in p2p format
int FilterParserThread::parseP2PFilterFile(QString m_filePath, libt::ip_filter &filter)
int FilterParserThread::parseP2PFilterFile(QString filePath, libt::ip_filter &filter)
{
int ruleCount = 0;
QFile file(m_filePath);
QFile file(filePath);
if (!file.exists()) return ruleCount;
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
@@ -257,10 +257,10 @@ int FilterParserThread::getlineInStream(QDataStream &stream, std::string &name,
}
// Parser for PeerGuardian ip filter in p2p format
int FilterParserThread::parseP2BFilterFile(QString m_filePath, libt::ip_filter &filter)
int FilterParserThread::parseP2BFilterFile(QString filePath, libt::ip_filter &filter)
{
int ruleCount = 0;
QFile file(m_filePath);
QFile file(filePath);
if (!file.exists()) return ruleCount;
if (!file.open(QIODevice::ReadOnly)) {
@@ -369,7 +369,7 @@ int FilterParserThread::parseP2BFilterFile(QString m_filePath, libt::ip_filter &
// * eMule IP list (DAT): http://wiki.phoenixlabs.org/wiki/DAT_Format
// * PeerGuardian Text (P2P): http://wiki.phoenixlabs.org/wiki/P2P_Format
// * PeerGuardian Binary (P2B): http://wiki.phoenixlabs.org/wiki/P2B_Format
void FilterParserThread::processFilterFile(QString _filePath)
void FilterParserThread::processFilterFile(QString filePath)
{
if (isRunning()) {
// Already parsing a filter, m_abort first
@@ -378,27 +378,11 @@ void FilterParserThread::processFilterFile(QString _filePath)
}
m_abort = false;
m_filePath = _filePath;
m_filePath = filePath;
// Run it
start();
}
void FilterParserThread::processFilterList(libt::session *s, const QStringList &IPs)
{
// First, import current filter
libt::ip_filter filter = s->get_ip_filter();
foreach (const QString &ip, IPs) {
qDebug("Manual ban of peer %s", ip.toLocal8Bit().constData());
boost::system::error_code ec;
libt::address addr = libt::address::from_string(ip.toLocal8Bit().constData(), ec);
Q_ASSERT(!ec);
if (!ec)
filter.add_rule(addr, addr, libt::ip_filter::blocked);
}
s->set_ip_filter(filter);
}
QString FilterParserThread::cleanupIPAddress(QString _ip)
{
_ip = _ip.trimmed();

View File

@@ -49,13 +49,7 @@ class FilterParserThread : public QThread
public:
FilterParserThread(libtorrent::session *s, QObject *parent = 0);
~FilterParserThread();
int parseDATFilterFile(QString filePath, libtorrent::ip_filter &filter);
int parseP2PFilterFile(QString filePath, libtorrent::ip_filter &filter);
int getlineInStream(QDataStream &stream, std::string &name, char delim);
int parseP2BFilterFile(QString filePath, libtorrent::ip_filter &filter);
void processFilterFile(QString _filePath);
static void processFilterList(libtorrent::session *s, const QStringList &IPs);
void processFilterFile(QString filePath);
signals:
void IPFilterParsed(int ruleCount);
@@ -66,6 +60,11 @@ protected:
void run();
private:
int parseDATFilterFile(QString filePath, libtorrent::ip_filter &filter);
int parseP2PFilterFile(QString filePath, libtorrent::ip_filter &filter);
int getlineInStream(QDataStream &stream, std::string &name, char delim);
int parseP2BFilterFile(QString filePath, libtorrent::ip_filter &filter);
libtorrent::session *m_session;
bool m_abort;
QString m_filePath;

File diff suppressed because it is too large Load Diff

View File

@@ -30,17 +30,23 @@
#ifndef BITTORRENT_SESSION_H
#define BITTORRENT_SESSION_H
#include <vector>
#include <libtorrent/version.hpp>
#include <QFile>
#include <QHash>
#include <QMap>
#include <QPointer>
#include <QVector>
#if LIBTORRENT_VERSION_NUM < 10100
#include <QMutex>
#include <QWaitCondition>
#endif
#include <QNetworkConfigurationManager>
#include <QPointer>
#include <QReadWriteLock>
#include <QStringList>
#include <QVector>
#include <QWaitCondition>
#include <libtorrent/version.hpp>
#include "base/settingvalue.h"
#include "base/tristatebool.h"
#include "base/types.h"
#include "torrentinfo.h"
@@ -52,19 +58,12 @@ namespace libtorrent
class entry;
struct add_torrent_params;
struct pe_settings;
struct session_settings;
struct session_status;
#if LIBTORRENT_VERSION_NUM < 10100
struct proxy_settings;
struct session_settings;
#else
namespace aux
{
struct proxy_settings;
}
typedef aux::proxy_settings proxy_settings;
struct settings_pack;
#endif
struct session_status;
class alert;
struct torrent_alert;
@@ -111,7 +110,6 @@ class FilterParserThread;
class BandwidthScheduler;
class Statistics;
class ResumeDataSavingManager;
class SettingsStorage;
enum MaxRatioAction
{
@@ -172,13 +170,6 @@ namespace BitTorrent
static void freeInstance();
static Session *instance();
bool isDHTEnabled() const;
bool isLSDEnabled() const;
bool isPexEnabled() const;
bool isQueueingEnabled() const;
qreal globalMaxRatio() const;
bool isAppendExtensionEnabled() const;
QString defaultSavePath() const;
void setDefaultSavePath(QString path);
QString tempPath() const;
@@ -219,8 +210,122 @@ namespace BitTorrent
bool isDisableAutoTMMWhenCategorySavePathChanged() const;
void setDisableAutoTMMWhenCategorySavePathChanged(bool value);
qreal globalMaxRatio() const;
void setGlobalMaxRatio(qreal ratio);
bool isDHTEnabled() const;
void setDHTEnabled(bool enabled);
bool isLSDEnabled() const;
void setLSDEnabled(bool enabled);
bool isPeXEnabled() const;
void setPeXEnabled(bool enabled);
bool isAddTorrentPaused() const;
void setAddTorrentPaused(bool value);
bool isTrackerEnabled() const;
void setTrackerEnabled(bool enabled);
bool isAppendExtensionEnabled() const;
void setAppendExtensionEnabled(bool enabled);
uint refreshInterval() const;
void setRefreshInterval(uint value);
bool isPreallocationEnabled() const;
void setPreallocationEnabled(bool enabled);
QString torrentExportDirectory() const;
void setTorrentExportDirectory(QString path);
QString finishedTorrentExportDirectory() const;
void setFinishedTorrentExportDirectory(QString path);
int globalDownloadSpeedLimit() const;
void setGlobalDownloadSpeedLimit(int limit);
int globalUploadSpeedLimit() const;
void setGlobalUploadSpeedLimit(int limit);
int altGlobalDownloadSpeedLimit() const;
void setAltGlobalDownloadSpeedLimit(int limit);
int altGlobalUploadSpeedLimit() const;
void setAltGlobalUploadSpeedLimit(int limit);
int downloadSpeedLimit() const;
void setDownloadSpeedLimit(int limit);
int uploadSpeedLimit() const;
void setUploadSpeedLimit(int limit);
bool isAltGlobalSpeedLimitEnabled() const;
void setAltGlobalSpeedLimitEnabled(bool enabled);
bool isBandwidthSchedulerEnabled() const;
void setBandwidthSchedulerEnabled(bool enabled);
uint saveResumeDataInterval() const;
void setSaveResumeDataInterval(uint value);
int port() const;
void setPort(int port);
bool useRandomPort() const;
void setUseRandomPort(bool value);
QString networkInterface() const;
void setNetworkInterface(const QString &interface);
QString networkInterfaceName() const;
void setNetworkInterfaceName(const QString &name);
QString networkInterfaceAddress() const;
void setNetworkInterfaceAddress(const QString &address);
bool isIPv6Enabled() const;
void setIPv6Enabled(bool enabled);
int encryption() const;
void setEncryption(int state);
bool isForceProxyEnabled() const;
void setForceProxyEnabled(bool enabled);
bool isProxyPeerConnectionsEnabled() const;
void setProxyPeerConnectionsEnabled(bool enabled);
bool isAddTrackersEnabled() const;
void setAddTrackersEnabled(bool enabled);
QString additionalTrackers() const;
void setAdditionalTrackers(const QString &trackers);
bool isIPFilteringEnabled() const;
void setIPFilteringEnabled(bool enabled);
QString IPFilterFile() const;
void setIPFilterFile(QString path);
bool announceToAllTrackers() const;
void setAnnounceToAllTrackers(bool val);
uint diskCacheSize() const;
void setDiskCacheSize(uint size);
uint diskCacheTTL() const;
void setDiskCacheTTL(uint ttl);
bool useOSCache() const;
void setUseOSCache(bool use);
bool isAnonymousModeEnabled() const;
void setAnonymousModeEnabled(bool enabled);
bool isQueueingSystemEnabled() const;
void setQueueingSystemEnabled(bool enabled);
bool ignoreSlowTorrentsForQueueing() const;
void setIgnoreSlowTorrentsForQueueing(bool ignore);
uint outgoingPortsMin() const;
void setOutgoingPortsMin(uint min);
uint outgoingPortsMax() const;
void setOutgoingPortsMax(uint max);
bool ignoreLimitsOnLAN() const;
void setIgnoreLimitsOnLAN(bool ignore);
bool includeOverheadInLimits() const;
void setIncludeOverheadInLimits(bool include);
QString announceIP() const;
void setAnnounceIP(const QString &ip);
bool isSuperSeedingEnabled() const;
void setSuperSeedingEnabled(bool enabled);
int maxConnections() const;
void setMaxConnections(int max);
int maxHalfOpenConnections() const;
void setMaxHalfOpenConnections(int max);
int maxConnectionsPerTorrent() const;
void setMaxConnectionsPerTorrent(int max);
int maxUploads() const;
void setMaxUploads(int max);
int maxUploadsPerTorrent() const;
void setMaxUploadsPerTorrent(int max);
int maxActiveDownloads() const;
void setMaxActiveDownloads(int max);
int maxActiveUploads() const;
void setMaxActiveUploads(int max);
int maxActiveTorrents() const;
void setMaxActiveTorrents(int max);
bool isUTPEnabled() const;
void setUTPEnabled(bool enabled);
bool isUTPRateLimited() const;
void setUTPRateLimited(bool limited);
bool isTrackerFilteringEnabled() const;
void setTrackerFilteringEnabled(bool enabled);
TorrentHandle *findTorrent(const InfoHash &hash) const;
QHash<InfoHash, TorrentHandle *> torrents() const;
@@ -231,19 +336,11 @@ namespace BitTorrent
CacheStatus cacheStatus() const;
quint64 getAlltimeDL() const;
quint64 getAlltimeUL() const;
int downloadRateLimit() const;
int uploadRateLimit() const;
bool isListening() const;
MaxRatioAction maxRatioAction() const;
void setMaxRatioAction(MaxRatioAction act);
void changeSpeedLimitMode(bool alternative);
void setDownloadRateLimit(int rate);
void setUploadRateLimit(int rate);
void setGlobalMaxRatio(qreal ratio);
void enableIPFilter(const QString &filterPath, bool force = false);
void disableIPFilter();
void banIP(const QString &ip);
bool isKnownTorrent(const InfoHash &hash) const;
@@ -304,7 +401,7 @@ namespace BitTorrent
void trackerAuthenticationRequired(BitTorrent::TorrentHandle *const torrent);
void recursiveTorrentDownloadPossible(BitTorrent::TorrentHandle *const torrent);
void speedLimitModeChanged(bool alternative);
void ipFilterParsed(bool error, int ruleCount);
void IPFilterParsed(bool error, int ruleCount);
void trackersAdded(BitTorrent::TorrentHandle *const torrent, const QList<BitTorrent::TrackerEntry> &trackers);
void trackersRemoved(BitTorrent::TorrentHandle *const torrent, const QList<BitTorrent::TrackerEntry> &trackers);
void trackersChanged(BitTorrent::TorrentHandle *const torrent);
@@ -316,7 +413,7 @@ namespace BitTorrent
void subcategoriesSupportChanged();
private slots:
void configure();
void configureDeferred();
void readAlerts();
void refresh();
void processBigRatios();
@@ -341,20 +438,24 @@ namespace BitTorrent
void initResumeFolder();
// Session configuration
void setSessionSettings();
void setProxySettings(libtorrent::proxy_settings proxySettings);
void adjustLimits();
Q_INVOKABLE void configure();
#if LIBTORRENT_VERSION_NUM < 10100
void configure(libtorrent::session_settings &sessionSettings);
void adjustLimits(libtorrent::session_settings &sessionSettings);
#else
void configure(libtorrent::settings_pack &settingsPack);
void adjustLimits(libtorrent::settings_pack &settingsPack);
#endif
void adjustLimits();
void processBannedIPs();
const QStringList getListeningIPs();
void setListeningPort();
void preAllocateAllFiles(bool b);
void setMaxConnectionsPerTorrent(int max);
void setMaxUploadsPerTorrent(int max);
void enableLSD(bool enable);
void enableDHT(bool enable);
void configureListeningInterface();
void changeSpeedLimitMode_impl(bool alternative);
void setAppendExtension(bool append);
void enableTracker(bool enable);
void enableBandwidthScheduler();
void populateAdditionalTrackers();
void enableIPFilter();
void disableIPFilter();
void startUpTorrents();
bool addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri,
@@ -364,7 +465,7 @@ namespace BitTorrent
void updateRatioTimer();
void exportTorrentFile(TorrentHandle *const torrent, TorrentExportFolder folder = TorrentExportFolder::Regular);
void saveTorrentResumeData(TorrentHandle *const torrent);
void saveTorrentResumeData(TorrentHandle *const torrent, bool finalSave = false);
void handleAlert(libtorrent::alert *a);
void dispatchTorrentAlert(libtorrent::alert *a);
@@ -389,35 +490,97 @@ namespace BitTorrent
void saveResumeData();
#if LIBTORRENT_VERSION_NUM < 10100
void dispatchAlerts(std::auto_ptr<libtorrent::alert> alertPtr);
void dispatchAlerts(libtorrent::alert *alertPtr);
#endif
void getPendingAlerts(std::vector<libtorrent::alert *> &out, ulong time = 0);
SettingsStorage *m_settings;
// BitTorrent
libtorrent::session *m_nativeSession;
bool m_LSDEnabled;
bool m_DHTEnabled;
bool m_PeXEnabled;
bool m_queueingEnabled;
bool m_torrentExportEnabled;
bool m_finishedTorrentExportEnabled;
bool m_preAllocateAll;
qreal m_globalMaxRatio;
bool m_deferredConfigureScheduled;
bool m_IPFilteringChanged;
#if LIBTORRENT_VERSION_NUM >= 10100
bool m_listenInterfaceChanged; // optimization
#endif
CachedSettingValue<bool> m_isDHTEnabled;
CachedSettingValue<bool> m_isLSDEnabled;
CachedSettingValue<bool> m_isPeXEnabled;
CachedSettingValue<bool> m_isIPFilteringEnabled;
CachedSettingValue<bool> m_isTrackerFilteringEnabled;
CachedSettingValue<QString> m_IPFilterFile;
CachedSettingValue<bool> m_announceToAllTrackers;
CachedSettingValue<uint> m_diskCacheSize;
CachedSettingValue<uint> m_diskCacheTTL;
CachedSettingValue<bool> m_useOSCache;
CachedSettingValue<bool> m_isAnonymousModeEnabled;
CachedSettingValue<bool> m_isQueueingEnabled;
CachedSettingValue<int> m_maxActiveDownloads;
CachedSettingValue<int> m_maxActiveUploads;
CachedSettingValue<int> m_maxActiveTorrents;
CachedSettingValue<bool> m_ignoreSlowTorrentsForQueueing;
CachedSettingValue<uint> m_outgoingPortsMin;
CachedSettingValue<uint> m_outgoingPortsMax;
CachedSettingValue<bool> m_ignoreLimitsOnLAN;
CachedSettingValue<bool> m_includeOverheadInLimits;
CachedSettingValue<QString> m_announceIP;
CachedSettingValue<bool> m_isSuperSeedingEnabled;
CachedSettingValue<int> m_maxConnections;
CachedSettingValue<int> m_maxHalfOpenConnections;
CachedSettingValue<int> m_maxUploads;
CachedSettingValue<int> m_maxConnectionsPerTorrent;
CachedSettingValue<int> m_maxUploadsPerTorrent;
CachedSettingValue<bool> m_isUTPEnabled;
CachedSettingValue<bool> m_isUTPRateLimited;
CachedSettingValue<bool> m_isAddTrackersEnabled;
CachedSettingValue<QString> m_additionalTrackers;
CachedSettingValue<qreal> m_globalMaxRatio;
CachedSettingValue<bool> m_isAddTorrentPaused;
CachedSettingValue<bool> m_isAppendExtensionEnabled;
CachedSettingValue<uint> m_refreshInterval;
CachedSettingValue<bool> m_isPreallocationEnabled;
CachedSettingValue<QString> m_torrentExportDirectory;
CachedSettingValue<QString> m_finishedTorrentExportDirectory;
CachedSettingValue<int> m_globalDownloadSpeedLimit;
CachedSettingValue<int> m_globalUploadSpeedLimit;
CachedSettingValue<int> m_altGlobalDownloadSpeedLimit;
CachedSettingValue<int> m_altGlobalUploadSpeedLimit;
CachedSettingValue<bool> m_isAltGlobalSpeedLimitEnabled;
CachedSettingValue<bool> m_isBandwidthSchedulerEnabled;
CachedSettingValue<uint> m_saveResumeDataInterval;
CachedSettingValue<int> m_port;
CachedSettingValue<bool> m_useRandomPort;
CachedSettingValue<QString> m_networkInterface;
CachedSettingValue<QString> m_networkInterfaceName;
CachedSettingValue<QString> m_networkInterfaceAddress;
CachedSettingValue<bool> m_isIPv6Enabled;
CachedSettingValue<int> m_encryption;
CachedSettingValue<bool> m_isForceProxyEnabled;
CachedSettingValue<bool> m_isProxyPeerConnectionsEnabled;
CachedSettingValue<QVariantMap> m_storedCategories;
CachedSettingValue<int> m_maxRatioAction;
CachedSettingValue<QString> m_defaultSavePath;
CachedSettingValue<QString> m_tempPath;
CachedSettingValue<bool> m_isSubcategoriesEnabled;
CachedSettingValue<bool> m_isTempPathEnabled;
CachedSettingValue<bool> m_isAutoTMMDisabledByDefault;
CachedSettingValue<bool> m_isDisableAutoTMMWhenCategoryChanged;
CachedSettingValue<bool> m_isDisableAutoTMMWhenDefaultSavePathChanged;
CachedSettingValue<bool> m_isDisableAutoTMMWhenCategorySavePathChanged;
CachedSettingValue<bool> m_isTrackerEnabled;
CachedSettingValue<QStringList> m_bannedIPs;
// Order is important. This needs to be declared after its CachedSettingsValue
// counterpart, because it uses it for initialization in the constructor
// initialization list.
const bool m_wasPexEnabled;
int m_numResumeData;
int m_extraLimit;
bool m_appendExtension;
uint m_refreshInterval;
MaxRatioAction m_maxRatioAction;
QList<BitTorrent::TrackerEntry> m_additionalTrackers;
QString m_defaultSavePath;
QString m_tempPath;
QString m_filterPath;
QList<BitTorrent::TrackerEntry> m_additionalTrackerList;
QString m_resumeFolderPath;
QFile m_resumeFolderLock;
QHash<InfoHash, QString> m_savePathsToRemove;
bool m_useProxy;
QTimer *m_refreshTimer;
QTimer *m_bigRatioTimer;
@@ -447,6 +610,8 @@ namespace BitTorrent
QNetworkConfigurationManager m_networkManager;
mutable QReadWriteLock m_lock;
static Session *m_instance;
};
}

View File

@@ -27,6 +27,8 @@
* exception statement from your version.
*/
#include <type_traits>
#include <QDebug>
#include <QStringList>
#include <QFile>
@@ -192,6 +194,31 @@ const qreal TorrentHandle::NO_RATIO_LIMIT = -1.;
const qreal TorrentHandle::MAX_RATIO = 9999.;
// The new libtorrent::create_torrent constructor appeared after 1.0.11 in RC_1_0
// and after 1.1.1 in RC_1_1. Since it fixed an ABI incompatibility with previous versions
// distros might choose to backport it onto 1.0.11 and 1.1.1 respectively.
// So we need a way to detect its presence without relying solely on the LIBTORRENT_VERSION_NUM.
// Relevant links:
// 1. https://github.com/arvidn/libtorrent/issues/1696
// 2. https://github.com/qbittorrent/qBittorrent/issues/6406
// The following can be removed after one or two libtorrent releases on each branch.
namespace
{
// new constructor is available
template<typename T, typename std::enable_if<std::is_constructible<T, libt::torrent_info, bool>::value, int>::type = 0>
T makeTorrentCreator(const libtorrent::torrent_info & ti)
{
return T(ti, true);
}
// new constructor isn't available
template<typename T, typename std::enable_if<!std::is_constructible<T, libt::torrent_info, bool>::value, int>::type = 0>
T makeTorrentCreator(const libtorrent::torrent_info & ti)
{
return T(ti);
}
}
TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle &nativeHandle,
const AddTorrentData &data)
: QObject(session)
@@ -485,8 +512,11 @@ bool TorrentHandle::needSaveResumeData() const
SAFE_RETURN(bool, need_save_resume_data, false);
}
void TorrentHandle::saveResumeData()
void TorrentHandle::saveResumeData(bool updateStatus)
{
if (updateStatus) // to update queue_position, see discussion in PR #6154
this->updateStatus();
SAFE_CALL(save_resume_data);
m_needSaveResumeData = false;
}
@@ -752,7 +782,7 @@ void TorrentHandle::updateState()
m_state = isSeed() ? TorrentState::PausedUploading : TorrentState::PausedDownloading;
}
else {
if (m_session->isQueueingEnabled() && isQueued() && !isChecking()) {
if (m_session->isQueueingSystemEnabled() && isQueued() && !isChecking()) {
m_state = isSeed() ? TorrentState::QueuedUploading : TorrentState::QueuedDownloading;
}
else {
@@ -915,26 +945,29 @@ int TorrentHandle::leechsCount() const
int TorrentHandle::totalSeedsCount() const
{
return m_nativeStatus.list_seeds;
return (m_nativeStatus.num_complete > 0) ? m_nativeStatus.num_complete : m_nativeStatus.list_seeds;
}
int TorrentHandle::totalPeersCount() const
{
return m_nativeStatus.list_peers;
int peers = m_nativeStatus.num_complete + m_nativeStatus.num_incomplete;
return (peers > 0) ? peers : m_nativeStatus.list_peers;
}
int TorrentHandle::totalLeechersCount() const
{
return (m_nativeStatus.list_peers - m_nativeStatus.list_seeds);
return (m_nativeStatus.num_incomplete > 0) ? m_nativeStatus.num_incomplete : (m_nativeStatus.list_peers - m_nativeStatus.list_seeds);
}
int TorrentHandle::completeCount() const
{
// additional info: https://github.com/qbittorrent/qBittorrent/pull/5300#issuecomment-267783646
return m_nativeStatus.num_complete;
}
int TorrentHandle::incompleteCount() const
{
// additional info: https://github.com/qbittorrent/qBittorrent/pull/5300#issuecomment-267783646
return m_nativeStatus.num_incomplete;
}
@@ -1280,7 +1313,7 @@ void TorrentHandle::moveStorage(const QString &newPath)
m_queuedPath = newPath;
}
else {
QString oldPath = nativeActualSavePath();
const QString oldPath = nativeActualSavePath();
if (QDir(oldPath) == QDir(newPath)) return;
qDebug("move storage: %s to %s", qPrintable(oldPath), qPrintable(newPath));
@@ -1312,7 +1345,7 @@ bool TorrentHandle::saveTorrentFile(const QString &path)
{
if (!m_torrentInfo.isValid()) return false;
libt::create_torrent torrentCreator(*(m_torrentInfo.nativeInfo()));
libt::create_torrent torrentCreator = makeTorrentCreator<libt::create_torrent>(*(m_torrentInfo.nativeInfo()));
libt::entry torrentEntry = torrentCreator.generate();
QVector<char> out;
@@ -1347,7 +1380,7 @@ void TorrentHandle::handleStorageMovedAlert(libtorrent::storage_moved_alert *p)
return;
}
QString newPath = Utils::String::fromStdString(p->path);
const QString newPath = Utils::String::fromStdString(p->path);
if (newPath != m_newPath) {
qWarning() << Q_FUNC_INFO << ": New path doesn't match a path in a queue.";
return;
@@ -1367,13 +1400,6 @@ void TorrentHandle::handleStorageMovedAlert(libtorrent::storage_moved_alert *p)
m_session->handleTorrentSavePathChanged(this);
}
// Attempt to remove old folder if empty
QDir oldSaveDir(Utils::Fs::fromNativePath(m_oldPath));
if (oldSaveDir != QDir(m_session->defaultSavePath())) {
qDebug("Attempting to remove %s", qPrintable(m_oldPath));
QDir().rmpath(m_oldPath);
}
while (!isMoveInProgress() && (m_renameCount == 0) && !m_moveFinishedTriggers.isEmpty())
m_moveFinishedTriggers.takeFirst()();
}
@@ -1702,6 +1728,11 @@ void TorrentHandle::manageIncompleteFiles()
{
const bool isAppendExtensionEnabled = m_session->isAppendExtensionEnabled();
QVector<qreal> fp = filesProgress();
if( fp.size() != filesCount() ) {
qDebug() << "skip manageIncompleteFiles because of invalid torrent meta-data or empty file-progress";
return;
}
for (int i = 0; i < filesCount(); ++i) {
QString name = filePath(i);
if (isAppendExtensionEnabled && (fileSize(i) > 0) && (fp[i] < 1)) {
@@ -1815,6 +1846,8 @@ void TorrentHandle::setDownloadLimit(int limit)
void TorrentHandle::setSuperSeeding(bool enable)
{
SAFE_CALL(super_seeding, enable)
if (superSeeding() != enable)
updateStatus();
}
void TorrentHandle::flushCache()

View File

@@ -351,7 +351,7 @@ namespace BitTorrent
void handleTempPathChanged();
void handleCategorySavePathChanged();
void handleAppendExtensionToggled();
void saveResumeData();
void saveResumeData(bool updateStatus = false);
private:
typedef boost::function<void ()> EventTrigger;

View File

@@ -239,7 +239,7 @@ QVector<int> TorrentInfo::fileIndicesForPiece(int pieceIndex) const
std::vector<libt::file_slice> files(
nativeInfo()->map_block(pieceIndex, 0, nativeInfo()->piece_size(pieceIndex)));
QVector<int> res;
res.reserve(files.size());
res.reserve(int(files.size()));
std::transform(files.begin(), files.end(), std::back_inserter(res),
[](const libt::file_slice &s) { return s.file_index; });

View File

@@ -35,7 +35,6 @@
#include <QUrlQuery>
#endif
#include <QDir>
#include <QTemporaryFile>
#include <QDebug>
#include "requestparser.h"

View File

@@ -33,6 +33,7 @@
#else
#include <QTcpSocket>
#endif
#include <QNetworkProxy>
#include "connection.h"
#include "server.h"
@@ -45,6 +46,10 @@ Server::Server(IRequestHandler *requestHandler, QObject *parent)
, m_https(false)
#endif
{
setProxy(QNetworkProxy::NoProxy);
#ifndef QT_NO_OPENSSL
QSslSocket::setDefaultCiphers(safeCipherList());
#endif
}
Server::~Server()
@@ -84,14 +89,15 @@ void Server::incomingConnection(int socketDescriptor)
if (serverSocket->setSocketDescriptor(socketDescriptor)) {
#ifndef QT_NO_OPENSSL
if (m_https) {
static_cast<QSslSocket*>(serverSocket)->setProtocol(QSsl::SecureProtocols);
static_cast<QSslSocket*>(serverSocket)->setPrivateKey(m_key);
static_cast<QSslSocket *>(serverSocket)->setProtocol(QSsl::SecureProtocols);
static_cast<QSslSocket *>(serverSocket)->setPrivateKey(m_key);
#ifdef QBT_USES_QT5
static_cast<QSslSocket*>(serverSocket)->setLocalCertificateChain(m_certificates);
static_cast<QSslSocket *>(serverSocket)->setLocalCertificateChain(m_certificates);
#else
static_cast<QSslSocket*>(serverSocket)->setLocalCertificate(m_certificates.first());
static_cast<QSslSocket *>(serverSocket)->setLocalCertificate(m_certificates.first());
#endif
static_cast<QSslSocket*>(serverSocket)->startServerEncryption();
static_cast<QSslSocket *>(serverSocket)->setPeerVerifyMode(QSslSocket::VerifyNone);
static_cast<QSslSocket *>(serverSocket)->startServerEncryption();
}
#endif
new Connection(serverSocket, m_requestHandler, this);
@@ -100,3 +106,26 @@ void Server::incomingConnection(int socketDescriptor)
serverSocket->deleteLater();
}
}
#ifndef QT_NO_OPENSSL
QList<QSslCipher> Server::safeCipherList() const
{
const QStringList badCiphers = {"idea", "rc4"};
const QList<QSslCipher> allCiphers = QSslSocket::supportedCiphers();
QList<QSslCipher> safeCiphers;
foreach (const QSslCipher &cipher, allCiphers) {
bool isSafe = true;
foreach (const QString &badCipher, badCiphers) {
if (cipher.name().contains(badCipher, Qt::CaseInsensitive)) {
isSafe = false;
break;
}
}
if (isSafe)
safeCiphers += cipher;
}
return safeCiphers;
}
#endif

View File

@@ -36,6 +36,7 @@
#include <QTcpServer>
#ifndef QT_NO_OPENSSL
#include <QSslCertificate>
#include <QSslCipher>
#include <QSslKey>
#endif
@@ -44,7 +45,7 @@ namespace Http
class IRequestHandler;
class Connection;
class Server : public QTcpServer
class Server: public QTcpServer
{
Q_OBJECT
Q_DISABLE_COPY(Server)
@@ -53,25 +54,27 @@ namespace Http
Server(IRequestHandler *requestHandler, QObject *parent = 0);
~Server();
#ifndef QT_NO_OPENSSL
#ifndef QT_NO_OPENSSL
void enableHttps(const QList<QSslCertificate> &certificates, const QSslKey &key);
void disableHttps();
#endif
private:
#ifdef QBT_USES_QT5
void incomingConnection(qintptr socketDescriptor);
#else
void incomingConnection(int socketDescriptor);
#endif
#endif
private:
IRequestHandler *m_requestHandler;
#ifndef QT_NO_OPENSSL
#ifdef QBT_USES_QT5
void incomingConnection(qintptr socketDescriptor);
#else
void incomingConnection(int socketDescriptor);
#endif
#ifndef QT_NO_OPENSSL
QList<QSslCipher> safeCipherList() const;
bool m_https;
QList<QSslCertificate> m_certificates;
QSslKey m_key;
#endif
#endif
};
}

View File

@@ -43,6 +43,10 @@ namespace Http
const QString HEADER_CONTENT_ENCODING = "Content-Encoding";
const QString HEADER_CONTENT_LENGTH = "Content-Length";
const QString HEADER_CACHE_CONTROL = "Cache-Control";
const QString HEADER_X_FRAME_OPTIONS = "X-Frame-Options";
const QString HEADER_X_XSS_PROTECTION = "X-XSS-Protection";
const QString HEADER_X_CONTENT_TYPE_OPTIONS = "X-Content-Type-Options";
const QString HEADER_CONTENT_SECURITY_POLICY = "Content-Security-Policy";
const QString CONTENT_TYPE_CSS = "text/css; charset=UTF-8";
const QString CONTENT_TYPE_GIF = "image/gif";

View File

@@ -1,6 +1,7 @@
#include "logger.h"
#include <QDateTime>
#include "base/utils/string.h"
Logger* Logger::m_instance = 0;
@@ -36,7 +37,7 @@ void Logger::addMessage(const QString &message, const Log::MsgType &type)
{
QWriteLocker locker(&lock);
Log::Msg temp = { msgCounter++, QDateTime::currentMSecsSinceEpoch(), type, message };
Log::Msg temp = { msgCounter++, QDateTime::currentMSecsSinceEpoch(), type, Utils::String::toHtmlEscaped(message) };
m_messages.push_back(temp);
if (m_messages.size() >= MAX_LOG_MESSAGES)
@@ -49,7 +50,7 @@ void Logger::addPeer(const QString &ip, bool blocked, const QString &reason)
{
QWriteLocker locker(&lock);
Log::Peer temp = { peerCounter++, QDateTime::currentMSecsSinceEpoch(), ip, blocked, reason };
Log::Peer temp = { peerCounter++, QDateTime::currentMSecsSinceEpoch(), Utils::String::toHtmlEscaped(ip), blocked, Utils::String::toHtmlEscaped(reason) };
m_peers.push_back(temp);
if (m_peers.size() >= MAX_LOG_MESSAGES)

View File

@@ -142,7 +142,7 @@ void DownloadHandler::init()
bool DownloadHandler::saveToFile(const QByteArray &replyData, QString &filePath)
{
QTemporaryFile *tmpfile = new QTemporaryFile;
QTemporaryFile *tmpfile = new QTemporaryFile(Utils::Fs::tempPath() + "XXXXXX");
if (!tmpfile->open()) {
delete tmpfile;
return false;

View File

@@ -27,20 +27,21 @@
* exception statement from your version.
*/
#include "downloadmanager.h"
#include <QDateTime>
#include <QNetworkRequest>
#include <QNetworkProxy>
#include <QNetworkCookieJar>
#include <QNetworkReply>
#include <QDebug>
#include <QNetworkCookie>
#include <QNetworkCookieJar>
#include <QNetworkProxy>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QSslError>
#include <QUrl>
#include <QDebug>
#include "base/preferences.h"
#include "downloadhandler.h"
#include "downloadmanager.h"
#include "proxyconfigurationmanager.h"
// Spoof Firefox 38 user agent to avoid web server banning
const char DEFAULT_USER_AGENT[] = "Mozilla/5.0 (X11; Linux i686; rv:38.0) Gecko/20100101 Firefox/38.0";
@@ -208,16 +209,16 @@ bool DownloadManager::deleteCookie(const QNetworkCookie &cookie)
void DownloadManager::applyProxySettings()
{
auto proxyManager = ProxyConfigurationManager::instance();
ProxyConfiguration proxyConfig = proxyManager->proxyConfiguration();
QNetworkProxy proxy;
const Preferences* const pref = Preferences::instance();
if (pref->isProxyEnabled() && !pref->isProxyOnlyForTorrents()) {
if (!proxyManager->isProxyOnlyForTorrents() && (proxyConfig.type != ProxyType::None)) {
// Proxy enabled
proxy.setHostName(pref->getProxyIp());
proxy.setPort(pref->getProxyPort());
proxy.setHostName(proxyConfig.ip);
proxy.setPort(proxyConfig.port);
// Default proxy type is HTTP, we must change if it is SOCKS5
const int proxyType = pref->getProxyType();
if ((proxyType == Proxy::SOCKS5) || (proxyType == Proxy::SOCKS5_PW)) {
if ((proxyConfig.type == ProxyType::SOCKS5) || (proxyConfig.type == ProxyType::SOCKS5_PW)) {
qDebug() << Q_FUNC_INFO << "using SOCKS proxy";
proxy.setType(QNetworkProxy::Socks5Proxy);
}
@@ -226,10 +227,10 @@ void DownloadManager::applyProxySettings()
proxy.setType(QNetworkProxy::HttpProxy);
}
// Authentication?
if (pref->isProxyAuthEnabled()) {
if (proxyManager->isAuthenticationRequired()) {
qDebug("Proxy requires authentication, authenticating");
proxy.setUser(pref->getProxyUsername());
proxy.setPassword(pref->getProxyPassword());
proxy.setUser(proxyConfig.username);
proxy.setPassword(proxyConfig.password);
}
}
else {

View File

@@ -45,7 +45,6 @@
static const char DATABASE_URL[] = "https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz";
static const char GEOIP_FOLDER[] = "GeoIP";
static const char GEOIP_FILENAME[] = "GeoLite2-Country.mmdb";
static const int CACHE_SIZE = 1000;
static const int UPDATE_INTERVAL = 30; // Days between database updates
using namespace Net;

View File

@@ -26,13 +26,17 @@
* exception statement from your version.
*/
#include "portforwarder.h"
#include <QDebug>
#include <libtorrent/session.hpp>
#include <libtorrent/version.hpp>
#include "base/logger.h"
#include "base/preferences.h"
#include "portforwarder.h"
#include "base/settingsstorage.h"
static const QString KEY_ENABLED = QLatin1String("Network/PortForwardingEnabled");
namespace libt = libtorrent;
using namespace Net;
@@ -42,8 +46,8 @@ PortForwarder::PortForwarder(libtorrent::session *provider, QObject *parent)
, m_active(false)
, m_provider(provider)
{
configure();
connect(Preferences::instance(), SIGNAL(changed()), SLOT(configure()));
if (SettingsStorage::instance()->loadValue(KEY_ENABLED, true).toBool())
start();
}
PortForwarder::~PortForwarder()
@@ -70,7 +74,24 @@ PortForwarder *PortForwarder::instance()
return m_instance;
}
void PortForwarder::addPort(qint16 port)
bool PortForwarder::isEnabled() const
{
return m_active;
}
void PortForwarder::setEnabled(bool enabled)
{
if (m_active != enabled) {
if (enabled)
start();
else
stop();
SettingsStorage::instance()->storeValue(KEY_ENABLED, enabled);
}
}
void PortForwarder::addPort(quint16 port)
{
if (!m_mappedPorts.contains(port)) {
m_mappedPorts.insert(port, 0);
@@ -79,7 +100,7 @@ void PortForwarder::addPort(qint16 port)
}
}
void PortForwarder::deletePort(qint16 port)
void PortForwarder::deletePort(quint16 port)
{
if (m_mappedPorts.contains(port)) {
if (m_active)
@@ -88,23 +109,19 @@ void PortForwarder::deletePort(qint16 port)
}
}
void PortForwarder::configure()
{
bool enable = Preferences::instance()->isUPnPEnabled();
if (m_active != enable) {
if (enable)
start();
else
stop();
}
}
void PortForwarder::start()
{
qDebug("Enabling UPnP / NAT-PMP");
#if LIBTORRENT_VERSION_NUM < 10100
m_provider->start_upnp();
m_provider->start_natpmp();
foreach (qint16 port, m_mappedPorts.keys())
#else
libt::settings_pack settingsPack = m_provider->get_settings();
settingsPack.set_bool(libt::settings_pack::enable_upnp, true);
settingsPack.set_bool(libt::settings_pack::enable_natpmp, true);
m_provider->apply_settings(settingsPack);
#endif
foreach (quint16 port, m_mappedPorts.keys())
m_mappedPorts[port] = m_provider->add_port_mapping(libt::session::tcp, port, port);
m_active = true;
Logger::instance()->addMessage(tr("UPnP / NAT-PMP support [ON]"), Log::INFO);
@@ -113,8 +130,15 @@ void PortForwarder::start()
void PortForwarder::stop()
{
qDebug("Disabling UPnP / NAT-PMP");
#if LIBTORRENT_VERSION_NUM < 10100
m_provider->stop_upnp();
m_provider->stop_natpmp();
#else
libt::settings_pack settingsPack = m_provider->get_settings();
settingsPack.set_bool(libt::settings_pack::enable_upnp, false);
settingsPack.set_bool(libt::settings_pack::enable_natpmp, false);
m_provider->apply_settings(settingsPack);
#endif
m_active = false;
Logger::instance()->addMessage(tr("UPnP / NAT-PMP support [OFF]"), Log::INFO);
}

View File

@@ -49,11 +49,11 @@ namespace Net
static void freeInstance();
static PortForwarder *instance();
void addPort(qint16 port);
void deletePort(qint16 port);
bool isEnabled() const;
void setEnabled(bool enabled);
private slots:
void configure();
void addPort(quint16 port);
void deletePort(quint16 port);
private:
explicit PortForwarder(libtorrent::session *const provider, QObject *parent = 0);
@@ -64,7 +64,7 @@ namespace Net
bool m_active;
libtorrent::session *m_provider;
QHash<qint16, int> m_mappedPorts;
QHash<quint16, int> m_mappedPorts;
static PortForwarder *m_instance;
};

View File

@@ -0,0 +1,163 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#include "proxyconfigurationmanager.h"
#include "base/settingsstorage.h"
#define SETTINGS_KEY(name) "Network/Proxy/" name
const QString KEY_ONLY_FOR_TORRENTS = SETTINGS_KEY("OnlyForTorrents");
const QString KEY_TYPE = SETTINGS_KEY("Type");
const QString KEY_IP = SETTINGS_KEY("IP");
const QString KEY_PORT = SETTINGS_KEY("Port");
const QString KEY_USERNAME = SETTINGS_KEY("Username");
const QString KEY_PASSWORD = SETTINGS_KEY("Password");
namespace
{
inline SettingsStorage *settings() { return SettingsStorage::instance(); }
inline bool isSameConfig(const Net::ProxyConfiguration &conf1, const Net::ProxyConfiguration &conf2)
{
return conf1.type == conf2.type
&& conf1.ip == conf2.ip
&& conf1.port == conf2.port
&& conf1.username == conf2.username
&& conf1.password == conf2.password;
}
}
using namespace Net;
ProxyConfigurationManager *ProxyConfigurationManager::m_instance = nullptr;
ProxyConfigurationManager::ProxyConfigurationManager(QObject *parent)
: QObject(parent)
{
m_isProxyOnlyForTorrents = settings()->loadValue(KEY_ONLY_FOR_TORRENTS, false).toBool();
m_config.type = static_cast<ProxyType>(
settings()->loadValue(KEY_TYPE, static_cast<int>(ProxyType::None)).toInt());
if ((m_config.type < ProxyType::None) || (m_config.type > ProxyType::SOCKS4))
m_config.type = ProxyType::None;
m_config.ip = settings()->loadValue(KEY_IP, "0.0.0.0").toString();
m_config.port = static_cast<ushort>(settings()->loadValue(KEY_PORT, 8080).toUInt());
m_config.username = settings()->loadValue(KEY_USERNAME).toString();
m_config.password = settings()->loadValue(KEY_PASSWORD).toString();
configureProxy();
}
void ProxyConfigurationManager::initInstance()
{
if (!m_instance)
m_instance = new ProxyConfigurationManager;
}
void ProxyConfigurationManager::freeInstance()
{
if (m_instance) {
delete m_instance;
m_instance = 0;
}
}
ProxyConfigurationManager *ProxyConfigurationManager::instance()
{
return m_instance;
}
ProxyConfiguration ProxyConfigurationManager::proxyConfiguration() const
{
return m_config;
}
void ProxyConfigurationManager::setProxyConfiguration(const ProxyConfiguration &config)
{
if (!isSameConfig(config, m_config)) {
m_config = config;
settings()->storeValue(KEY_TYPE, static_cast<int>(config.type));
settings()->storeValue(KEY_IP, config.ip);
settings()->storeValue(KEY_PORT, config.port);
settings()->storeValue(KEY_USERNAME, config.username);
settings()->storeValue(KEY_PASSWORD, config.password);
configureProxy();
emit proxyConfigurationChanged();
}
}
bool ProxyConfigurationManager::isProxyOnlyForTorrents() const
{
return m_isProxyOnlyForTorrents || (m_config.type == ProxyType::SOCKS4);
}
void ProxyConfigurationManager::setProxyOnlyForTorrents(bool onlyForTorrents)
{
if (m_isProxyOnlyForTorrents != onlyForTorrents) {
settings()->storeValue(KEY_ONLY_FOR_TORRENTS, onlyForTorrents);
m_isProxyOnlyForTorrents = onlyForTorrents;
}
}
bool ProxyConfigurationManager::isAuthenticationRequired() const
{
return m_config.type == ProxyType::SOCKS5_PW
|| m_config.type == ProxyType::HTTP_PW;
}
void ProxyConfigurationManager::configureProxy()
{
// Define environment variables for urllib in search engine plugins
QString proxyStrHTTP, proxyStrSOCK;
if (!m_isProxyOnlyForTorrents) {
switch (m_config.type) {
case ProxyType::HTTP_PW:
proxyStrHTTP = QString("http://%1:%2@%3:%4").arg(m_config.username)
.arg(m_config.password).arg(m_config.ip).arg(m_config.port);
break;
case ProxyType::HTTP:
proxyStrHTTP = QString("http://%1:%2").arg(m_config.ip).arg(m_config.port);
break;
case ProxyType::SOCKS5:
proxyStrSOCK = QString("%1:%2").arg(m_config.ip).arg(m_config.port);
break;
case ProxyType::SOCKS5_PW:
proxyStrSOCK = QString("%1:%2@%3:%4").arg(m_config.username)
.arg(m_config.password).arg(m_config.ip).arg(m_config.port);
break;
default:
qDebug("Disabling HTTP communications proxy");
}
qDebug("HTTP communications proxy string: %s"
, qPrintable((m_config.type == ProxyType::SOCKS5) || (m_config.type == ProxyType::SOCKS5_PW)
? proxyStrSOCK : proxyStrHTTP));
}
qputenv("http_proxy", proxyStrHTTP.toLocal8Bit());
qputenv("https_proxy", proxyStrHTTP.toLocal8Bit());
qputenv("sock_proxy", proxyStrSOCK.toLocal8Bit());
}

View File

@@ -0,0 +1,87 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#ifndef NET_PROXYCONFIGURATIONMANAGER_H
#define NET_PROXYCONFIGURATIONMANAGER_H
#include <QObject>
namespace Net
{
enum class ProxyType
{
None = 0,
HTTP = 1,
SOCKS5 = 2,
HTTP_PW = 3,
SOCKS5_PW = 4,
SOCKS4 = 5
};
struct ProxyConfiguration
{
ProxyType type = ProxyType::None;
QString ip = "0.0.0.0";
ushort port = 8080;
QString username;
QString password;
};
class ProxyConfigurationManager: public QObject
{
Q_OBJECT
Q_DISABLE_COPY(ProxyConfigurationManager)
explicit ProxyConfigurationManager(QObject *parent = nullptr);
~ProxyConfigurationManager() = default;
public:
static void initInstance();
static void freeInstance();
static ProxyConfigurationManager *instance();
ProxyConfiguration proxyConfiguration() const;
void setProxyConfiguration(const ProxyConfiguration &config);
bool isProxyOnlyForTorrents() const;
void setProxyOnlyForTorrents(bool onlyForTorrents);
bool isAuthenticationRequired() const;
signals:
void proxyConfigurationChanged();
private:
void configureProxy();
static ProxyConfigurationManager *m_instance;
ProxyConfiguration m_config;
bool m_isProxyOnlyForTorrents;
};
}
#endif // NET_PROXYCONFIGURATIONMANAGER_H

View File

@@ -53,7 +53,9 @@
namespace
{
const short DEFAULT_PORT = 25;
#ifndef QT_NO_OPENSSL
const short DEFAULT_PORT_SSL = 465;
#endif
QByteArray hmacMD5(QByteArray key, const QByteArray &msg)
{
@@ -98,12 +100,12 @@ Smtp::Smtp(QObject *parent)
, m_authType(AuthPlain)
{
static bool needToRegisterMetaType = true;
if (needToRegisterMetaType) {
qRegisterMetaType<QAbstractSocket::SocketError>();
needToRegisterMetaType = false;
}
#ifndef QT_NO_OPENSSL
m_socket = new QSslSocket(this);
#else

View File

@@ -31,8 +31,9 @@
*/
#include <QCryptographicHash>
#include <QPair>
#include <QDir>
#include <QLocale>
#include <QPair>
#include <QSettings>
#ifndef DISABLE_GUI
@@ -50,8 +51,6 @@
#include <CoreServices/CoreServices.h>
#endif
#include <cstdlib>
#include "utils/fs.h"
#include "utils/misc.h"
#include "settingsstorage.h"
@@ -60,10 +59,7 @@
Preferences* Preferences::m_instance = 0;
Preferences::Preferences()
: m_randomPort(rand() % 64512 + 1024)
{
}
Preferences::Preferences() {}
Preferences *Preferences::instance()
{
@@ -97,7 +93,7 @@ void Preferences::setValue(const QString &key, const QVariant &value)
// General options
QString Preferences::getLocale() const
{
return value("Preferences/General/Locale").toString();
return value("Preferences/General/Locale", QLocale::system().name()).toString();
}
void Preferences::setLocale(const QString &locale)
@@ -165,16 +161,6 @@ void Preferences::setHideZeroComboValues(int n)
setValue("Preferences/General/HideZeroComboValues", n);
}
bool Preferences::useRandomPort() const
{
return value("Preferences/General/UseRandomPort", false).toBool();
}
void Preferences::setRandomPort(bool b)
{
setValue("Preferences/General/UseRandomPort", b);
}
bool Preferences::systrayIntegration() const
{
return value("Preferences/General/SystrayEnabled", true).toBool();
@@ -267,16 +253,6 @@ void Preferences::setWinStartup(bool b)
#endif
// Downloads
bool Preferences::useIncompleteFilesExtension() const
{
return value("Preferences/Downloads/UseIncompleteExtension", false).toBool();
}
void Preferences::useIncompleteFilesExtension(bool enabled)
{
setValue("Preferences/Downloads/UseIncompleteExtension", enabled);
}
QString Preferences::lastLocationPath() const
{
return Utils::Fs::fromNativePath(value("Preferences/Downloads/LastLocationPath").toString());
@@ -287,16 +263,6 @@ void Preferences::setLastLocationPath(const QString &path)
setValue("Preferences/Downloads/LastLocationPath", Utils::Fs::fromNativePath(path));
}
bool Preferences::preAllocateAllFiles() const
{
return value("Preferences/Downloads/PreAllocation", false).toBool();
}
void Preferences::preAllocateAllFiles(bool enabled)
{
return setValue("Preferences/Downloads/PreAllocation", enabled);
}
QVariantHash Preferences::getScanDirs() const
{
return value("Preferences/Downloads/ScanDirsV2").toHash();
@@ -318,36 +284,6 @@ void Preferences::setScanDirsLastPath(const QString &path)
setValue("Preferences/Downloads/ScanDirsLastPath", Utils::Fs::fromNativePath(path));
}
bool Preferences::isTorrentExportEnabled() const
{
return !value("Preferences/Downloads/TorrentExportDir").toString().isEmpty();
}
QString Preferences::getTorrentExportDir() const
{
return Utils::Fs::fromNativePath(value("Preferences/Downloads/TorrentExportDir").toString());
}
void Preferences::setTorrentExportDir(QString path)
{
setValue("Preferences/Downloads/TorrentExportDir", Utils::Fs::fromNativePath(path.trimmed()));
}
bool Preferences::isFinishedTorrentExportEnabled() const
{
return !value("Preferences/Downloads/FinishedTorrentExportDir").toString().isEmpty();
}
QString Preferences::getFinishedTorrentExportDir() const
{
return Utils::Fs::fromNativePath(value("Preferences/Downloads/FinishedTorrentExportDir").toString());
}
void Preferences::setFinishedTorrentExportDir(QString path)
{
setValue("Preferences/Downloads/FinishedTorrentExportDir", Utils::Fs::fromNativePath(path.trimmed()));
}
bool Preferences::isMailNotificationEnabled() const
{
return value("Preferences/MailNotification/enabled", false).toBool();
@@ -438,97 +374,6 @@ void Preferences::setActionOnDblClOnTorrentFn(int act)
setValue("Preferences/Downloads/DblClOnTorFn", act);
}
// Connection options
int Preferences::getSessionPort() const
{
if (useRandomPort())
return m_randomPort;
return value("Preferences/Connection/PortRangeMin", 8999).toInt();
}
void Preferences::setSessionPort(int port)
{
setValue("Preferences/Connection/PortRangeMin", port);
}
bool Preferences::isUPnPEnabled() const
{
return value("Preferences/Connection/UPnP", true).toBool();
}
void Preferences::setUPnPEnabled(bool enabled)
{
setValue("Preferences/Connection/UPnP", enabled);
}
int Preferences::getGlobalDownloadLimit() const
{
return value("Preferences/Connection/GlobalDLLimit", -1).toInt();
}
void Preferences::setGlobalDownloadLimit(int limit)
{
if (limit <= 0)
limit = -1;
setValue("Preferences/Connection/GlobalDLLimit", limit);
}
int Preferences::getGlobalUploadLimit() const
{
return value("Preferences/Connection/GlobalUPLimit", -1).toInt();
}
void Preferences::setGlobalUploadLimit(int limit)
{
if (limit <= 0)
limit = -1;
setValue("Preferences/Connection/GlobalUPLimit", limit);
}
int Preferences::getAltGlobalDownloadLimit() const
{
return value("Preferences/Connection/GlobalDLLimitAlt", 10).toInt();
}
void Preferences::setAltGlobalDownloadLimit(int limit)
{
if (limit <= 0)
limit = -1;
setValue("Preferences/Connection/GlobalDLLimitAlt", limit);
}
int Preferences::getAltGlobalUploadLimit() const
{
return value("Preferences/Connection/GlobalUPLimitAlt", 10).toInt();
}
void Preferences::setAltGlobalUploadLimit(int limit)
{
if (limit <= 0)
limit = -1;
setValue("Preferences/Connection/GlobalUPLimitAlt", limit);
}
bool Preferences::isAltBandwidthEnabled() const
{
return value("Preferences/Connection/alt_speeds_on", false).toBool();
}
void Preferences::setAltBandwidthEnabled(bool enabled)
{
setValue("Preferences/Connection/alt_speeds_on", enabled);
}
bool Preferences::isSchedulerEnabled() const
{
return value("Preferences/Scheduler/Enabled", false).toBool();
}
void Preferences::setSchedulerEnabled(bool enabled)
{
setValue("Preferences/Scheduler/Enabled", enabled);
}
QTime Preferences::getSchedulerStartTime() const
{
return value("Preferences/Scheduler/start_time", QTime(8,0)).toTime();
@@ -559,286 +404,6 @@ void Preferences::setSchedulerDays(scheduler_days days)
setValue("Preferences/Scheduler/days", (int)days);
}
// Proxy options
bool Preferences::isProxyEnabled() const
{
return getProxyType() > 0;
}
bool Preferences::isProxyAuthEnabled() const
{
return value("Preferences/Connection/Proxy/Authentication", false).toBool();
}
void Preferences::setProxyAuthEnabled(bool enabled)
{
setValue("Preferences/Connection/Proxy/Authentication", enabled);
}
QString Preferences::getProxyIp() const
{
return value("Preferences/Connection/Proxy/IP", "0.0.0.0").toString();
}
void Preferences::setProxyIp(const QString &ip)
{
setValue("Preferences/Connection/Proxy/IP", ip);
}
unsigned short Preferences::getProxyPort() const
{
return value("Preferences/Connection/Proxy/Port", 8080).toInt();
}
void Preferences::setProxyPort(unsigned short port)
{
setValue("Preferences/Connection/Proxy/Port", port);
}
QString Preferences::getProxyUsername() const
{
return value("Preferences/Connection/Proxy/Username").toString();
}
void Preferences::setProxyUsername(const QString &username)
{
setValue("Preferences/Connection/Proxy/Username", username);
}
QString Preferences::getProxyPassword() const
{
return value("Preferences/Connection/Proxy/Password").toString();
}
void Preferences::setProxyPassword(const QString &password)
{
setValue("Preferences/Connection/Proxy/Password", password);
}
int Preferences::getProxyType() const
{
return value("Preferences/Connection/ProxyType", 0).toInt();
}
void Preferences::setProxyType(int type)
{
setValue("Preferences/Connection/ProxyType", type);
}
bool Preferences::proxyPeerConnections() const
{
return value("Preferences/Connection/ProxyPeerConnections", false).toBool();
}
void Preferences::setProxyPeerConnections(bool enabled)
{
setValue("Preferences/Connection/ProxyPeerConnections", enabled);
}
bool Preferences::getForceProxy() const
{
return value("Preferences/Connection/ProxyForce", true).toBool();
}
void Preferences::setForceProxy(bool enabled)
{
setValue("Preferences/Connection/ProxyForce", enabled);
}
void Preferences::setProxyOnlyForTorrents(bool enabled)
{
setValue("Preferences/Connection/ProxyOnlyForTorrents", enabled);
}
bool Preferences::isProxyOnlyForTorrents() const
{
return value("Preferences/Connection/ProxyOnlyForTorrents", false).toBool();
}
// Bittorrent options
int Preferences::getMaxConnecs() const
{
return value("Preferences/Bittorrent/MaxConnecs", 500).toInt();
}
void Preferences::setMaxConnecs(int val)
{
if (val <= 0)
val = -1;
setValue("Preferences/Bittorrent/MaxConnecs", val);
}
int Preferences::getMaxConnecsPerTorrent() const
{
return value("Preferences/Bittorrent/MaxConnecsPerTorrent", 100).toInt();
}
void Preferences::setMaxConnecsPerTorrent(int val)
{
if (val <= 0)
val = -1;
setValue("Preferences/Bittorrent/MaxConnecsPerTorrent", val);
}
int Preferences::getMaxUploads() const
{
return value("Preferences/Bittorrent/MaxUploads", -1).toInt();
}
void Preferences::setMaxUploads(int val)
{
if (val <= 0)
val = -1;
setValue("Preferences/Bittorrent/MaxUploads", val);
}
int Preferences::getMaxUploadsPerTorrent() const
{
return value("Preferences/Bittorrent/MaxUploadsPerTorrent", -1).toInt();
}
void Preferences::setMaxUploadsPerTorrent(int val)
{
if (val <= 0)
val = -1;
setValue("Preferences/Bittorrent/MaxUploadsPerTorrent", val);
}
bool Preferences::isuTPEnabled() const
{
return value("Preferences/Bittorrent/uTP", true).toBool();
}
void Preferences::setuTPEnabled(bool enabled)
{
setValue("Preferences/Bittorrent/uTP", enabled);
}
bool Preferences::isuTPRateLimited() const
{
return value("Preferences/Bittorrent/uTP_rate_limited", true).toBool();
}
void Preferences::setuTPRateLimited(bool enabled)
{
setValue("Preferences/Bittorrent/uTP_rate_limited", enabled);
}
bool Preferences::isDHTEnabled() const
{
return value("Preferences/Bittorrent/DHT", true).toBool();
}
void Preferences::setDHTEnabled(bool enabled)
{
setValue("Preferences/Bittorrent/DHT", enabled);
}
bool Preferences::isPeXEnabled() const
{
return value("Preferences/Bittorrent/PeX", true).toBool();
}
void Preferences::setPeXEnabled(bool enabled)
{
setValue("Preferences/Bittorrent/PeX", enabled);
}
bool Preferences::isLSDEnabled() const
{
return value("Preferences/Bittorrent/LSD", true).toBool();
}
void Preferences::setLSDEnabled(bool enabled)
{
setValue("Preferences/Bittorrent/LSD", enabled);
}
int Preferences::getEncryptionSetting() const
{
return value("Preferences/Bittorrent/Encryption", 0).toInt();
}
void Preferences::setEncryptionSetting(int val)
{
setValue("Preferences/Bittorrent/Encryption", val);
}
bool Preferences::isAddTrackersEnabled() const
{
return value("Preferences/Bittorrent/AddTrackers", false).toBool();
}
void Preferences::setAddTrackersEnabled(bool enabled)
{
setValue("Preferences/Bittorrent/AddTrackers", enabled);
}
QString Preferences::getTrackersList() const
{
return value("Preferences/Bittorrent/TrackersList").toString();
}
void Preferences::setTrackersList(const QString &val)
{
setValue("Preferences/Bittorrent/TrackersList", val);
}
qreal Preferences::getGlobalMaxRatio() const
{
return value("Preferences/Bittorrent/MaxRatio", -1).toReal();
}
void Preferences::setGlobalMaxRatio(qreal ratio)
{
setValue("Preferences/Bittorrent/MaxRatio", ratio);
}
// IP Filter
bool Preferences::isFilteringEnabled() const
{
return value("Preferences/IPFilter/Enabled", false).toBool();
}
void Preferences::setFilteringEnabled(bool enabled)
{
setValue("Preferences/IPFilter/Enabled", enabled);
}
bool Preferences::isFilteringTrackerEnabled() const
{
return value("Preferences/IPFilter/FilterTracker", false).toBool();
}
void Preferences::setFilteringTrackerEnabled(bool enabled)
{
setValue("Preferences/IPFilter/FilterTracker", enabled);
}
QString Preferences::getFilter() const
{
return Utils::Fs::fromNativePath(value("Preferences/IPFilter/File").toString());
}
void Preferences::setFilter(const QString &path)
{
setValue("Preferences/IPFilter/File", Utils::Fs::fromNativePath(path));
}
QStringList Preferences::bannedIPs() const
{
return value("Preferences/IPFilter/BannedIPs").toStringList();
}
void Preferences::banIP(const QString &ip)
{
QStringList banned_ips = value("Preferences/IPFilter/BannedIPs").toStringList();
if (!banned_ips.contains(ip)) {
banned_ips << ip;
setValue("Preferences/IPFilter/BannedIPs", banned_ips);
}
}
// Search
bool Preferences::isSearchEnabled() const
{
@@ -850,63 +415,6 @@ void Preferences::setSearchEnabled(bool enabled)
setValue("Preferences/Search/SearchEnabled", enabled);
}
// Queueing system
bool Preferences::isQueueingSystemEnabled() const
{
return value("Preferences/Queueing/QueueingEnabled", true).toBool();
}
void Preferences::setQueueingSystemEnabled(bool enabled)
{
setValue("Preferences/Queueing/QueueingEnabled", enabled);
}
int Preferences::getMaxActiveDownloads() const
{
return value("Preferences/Queueing/MaxActiveDownloads", 3).toInt();
}
void Preferences::setMaxActiveDownloads(int val)
{
if (val < 0)
val = -1;
setValue("Preferences/Queueing/MaxActiveDownloads", val);
}
int Preferences::getMaxActiveUploads() const
{
return value("Preferences/Queueing/MaxActiveUploads", 3).toInt();
}
void Preferences::setMaxActiveUploads(int val)
{
if (val < 0)
val = -1;
setValue("Preferences/Queueing/MaxActiveUploads", val);
}
int Preferences::getMaxActiveTorrents() const
{
return value("Preferences/Queueing/MaxActiveTorrents", 5).toInt();
}
void Preferences::setMaxActiveTorrents(int val)
{
if (val < 0)
val = -1;
setValue("Preferences/Queueing/MaxActiveTorrents", val);
}
bool Preferences::ignoreSlowTorrentsForQueueing() const
{
return value("Preferences/Queueing/IgnoreSlowTorrents", false).toBool();
}
void Preferences::setIgnoreSlowTorrentsForQueueing(bool ignore)
{
setValue("Preferences/Queueing/IgnoreSlowTorrents", ignore);
}
bool Preferences::isWebUiEnabled() const
{
#ifdef DISABLE_GUI
@@ -943,7 +451,11 @@ void Preferences::setWebUiPort(quint16 port)
bool Preferences::useUPnPForWebUIPort() const
{
#ifdef DISABLE_GUI
return value("Preferences/WebUI/UseUPnP", true).toBool();
#else
return value("Preferences/WebUI/UseUPnP", false).toBool();
#endif
}
void Preferences::setUPnPForWebUIPort(bool enabled)
@@ -1164,111 +676,6 @@ void Preferences::setDontConfirmAutoExit(bool dontConfirmAutoExit)
setValue("ShutdownConfirmDlg/DontConfirmAutoExit", dontConfirmAutoExit);
}
uint Preferences::diskCacheSize() const
{
uint size = value("Preferences/Downloads/DiskWriteCacheSize", 0).toUInt();
// These macros may not be available on compilers other than MSVC and GCC
#if defined(__x86_64__) || defined(_M_X64)
size = qMin(size, (uint) 4096); // 4GiB
#else
// When build as 32bit binary, set the maximum at less than 2GB to prevent crashes
// allocate 1536MiB and leave 512MiB to the rest of program data in RAM
size = qMin(size, (uint) 1536);
#endif
return size;
}
void Preferences::setDiskCacheSize(uint size)
{
#if defined(__x86_64__) || defined(_M_X64)
size = qMin(size, (uint) 4096); // 4GiB
#else
// allocate 1536MiB and leave 512MiB to the rest of program data in RAM
size = qMin(size, (uint) 1536);
#endif
setValue("Preferences/Downloads/DiskWriteCacheSize", size);
}
uint Preferences::diskCacheTTL() const
{
return value("Preferences/Downloads/DiskWriteCacheTTL", 60).toUInt();
}
void Preferences::setDiskCacheTTL(uint ttl)
{
setValue("Preferences/Downloads/DiskWriteCacheTTL", ttl);
}
bool Preferences::osCache() const
{
return value("Preferences/Advanced/osCache", true).toBool();
}
void Preferences::setOsCache(bool enable)
{
setValue("Preferences/Advanced/osCache", enable);
}
uint Preferences::saveResumeDataInterval() const
{
return value("Preferences/Downloads/SaveResumeDataInterval", 3).toUInt();
}
void Preferences::setSaveResumeDataInterval(uint m)
{
setValue("Preferences/Downloads/SaveResumeDataInterval", m);
}
uint Preferences::outgoingPortsMin() const
{
return value("Preferences/Advanced/OutgoingPortsMin", 0).toUInt();
}
void Preferences::setOutgoingPortsMin(uint val)
{
setValue("Preferences/Advanced/OutgoingPortsMin", val);
}
uint Preferences::outgoingPortsMax() const
{
return value("Preferences/Advanced/OutgoingPortsMax", 0).toUInt();
}
void Preferences::setOutgoingPortsMax(uint val)
{
setValue("Preferences/Advanced/OutgoingPortsMax", val);
}
bool Preferences::getIgnoreLimitsOnLAN() const
{
return value("Preferences/Advanced/IgnoreLimitsLAN", true).toBool();
}
void Preferences::setIgnoreLimitsOnLAN(bool ignore)
{
setValue("Preferences/Advanced/IgnoreLimitsLAN", ignore);
}
bool Preferences::includeOverheadInLimits() const
{
return value("Preferences/Advanced/IncludeOverhead", false).toBool();
}
void Preferences::includeOverheadInLimits(bool include)
{
setValue("Preferences/Advanced/IncludeOverhead", include);
}
bool Preferences::trackerExchangeEnabled() const
{
return value("Preferences/Advanced/LtTrackerExchange", false).toBool();
}
void Preferences::setTrackerExchangeEnabled(bool enable)
{
setValue("Preferences/Advanced/LtTrackerExchange", enable);
}
bool Preferences::recheckTorrentsOnCompletion() const
{
return value("Preferences/Advanced/RecheckOnCompletion", false).toBool();
@@ -1279,16 +686,6 @@ void Preferences::recheckTorrentsOnCompletion(bool recheck)
setValue("Preferences/Advanced/RecheckOnCompletion", recheck);
}
unsigned int Preferences::getRefreshInterval() const
{
return value("Preferences/General/RefreshInterval", 1500).toUInt();
}
void Preferences::setRefreshInterval(uint interval)
{
setValue("Preferences/General/RefreshInterval", interval);
}
bool Preferences::resolvePeerCountries() const
{
return value("Preferences/Connection/ResolvePeerCountries", true).toBool();
@@ -1309,101 +706,6 @@ void Preferences::resolvePeerHostNames(bool resolve)
setValue("Preferences/Connection/ResolvePeerHostNames", resolve);
}
int Preferences::getMaxHalfOpenConnections() const
{
const int val = value("Preferences/Connection/MaxHalfOpenConnec", 20).toInt();
if (val <= 0)
return -1;
return val;
}
void Preferences::setMaxHalfOpenConnections(int value)
{
if (value <= 0)
value = -1;
setValue("Preferences/Connection/MaxHalfOpenConnec", value);
}
QString Preferences::getNetworkInterface() const
{
return value("Preferences/Connection/Interface").toString();
}
void Preferences::setNetworkInterface(const QString& iface)
{
setValue("Preferences/Connection/Interface", iface);
}
QString Preferences::getNetworkInterfaceName() const
{
return value("Preferences/Connection/InterfaceName").toString();
}
void Preferences::setNetworkInterfaceName(const QString& iface)
{
setValue("Preferences/Connection/InterfaceName", iface);
}
void Preferences::setNetworkInterfaceAddress(const QString& addr)
{
setValue("Preferences/Connection/InterfaceAddress", addr);
}
QString Preferences::getNetworkInterfaceAddress() const
{
return value("Preferences/Connection/InterfaceAddress").toString();
}
bool Preferences::getListenIPv6() const
{
return value("Preferences/Connection/InterfaceListenIPv6", false).toBool();
}
void Preferences::setListenIPv6(bool enable)
{
setValue("Preferences/Connection/InterfaceListenIPv6", enable);
}
QString Preferences::getNetworkAddress() const
{
return value("Preferences/Connection/InetAddress").toString();
}
void Preferences::setNetworkAddress(const QString& addr)
{
setValue("Preferences/Connection/InetAddress", addr);
}
bool Preferences::isAnonymousModeEnabled() const
{
return value("Preferences/Advanced/AnonymousMode", false).toBool();
}
void Preferences::enableAnonymousMode(bool enabled)
{
setValue("Preferences/Advanced/AnonymousMode", enabled);
}
bool Preferences::isSuperSeedingEnabled() const
{
return value("Preferences/Advanced/SuperSeeding", false).toBool();
}
void Preferences::enableSuperSeeding(bool enabled)
{
setValue("Preferences/Advanced/SuperSeeding", enabled);
}
bool Preferences::announceToAllTrackers() const
{
return value("Preferences/Advanced/AnnounceToAllTrackers", true).toBool();
}
void Preferences::setAnnounceToAllTrackers(bool enabled)
{
setValue("Preferences/Advanced/AnnounceToAllTrackers", enabled);
}
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
bool Preferences::useSystemIconTheme() const
{
@@ -1710,16 +1012,6 @@ void Preferences::setMagnetLinkAssoc()
}
#endif
bool Preferences::isTrackerEnabled() const
{
return value("Preferences/Advanced/trackerEnabled", false).toBool();
}
void Preferences::setTrackerEnabled(bool enabled)
{
setValue("Preferences/Advanced/trackerEnabled", enabled);
}
int Preferences::getTrackerPort() const
{
return value("Preferences/Advanced/trackerPort", 9000).toInt();
@@ -1997,7 +1289,7 @@ void Preferences::setRssOpenFolders(const QStringList &folders)
setValue("Rss/open_folders", folders);
}
QByteArray Preferences::getRssHSplitterState() const
QByteArray Preferences::getRssSideSplitterState() const
{
#ifdef QBT_USES_QT5
return value("Rss/qt5/splitter_h").toByteArray();
@@ -2006,7 +1298,7 @@ QByteArray Preferences::getRssHSplitterState() const
#endif
}
void Preferences::setRssHSplitterState(const QByteArray &state)
void Preferences::setRssSideSplitterState(const QByteArray &state)
{
#ifdef QBT_USES_QT5
setValue("Rss/qt5/splitter_h", state);
@@ -2015,32 +1307,40 @@ void Preferences::setRssHSplitterState(const QByteArray &state)
#endif
}
QByteArray Preferences::getRssVSplitterState() const
QByteArray Preferences::getRssMainSplitterState() const
{
#ifdef QBT_USES_QT5
return value("Rss/qt5/splitter_v").toByteArray();
return value("Rss/qt5/splitterMain").toByteArray();
#else
return value("Rss/splitter_v").toByteArray();
return value("Rss/splitterMain").toByteArray();
#endif
}
void Preferences::setRssVSplitterState(const QByteArray &state)
void Preferences::setRssMainSplitterState(const QByteArray &state)
{
#ifdef QBT_USES_QT5
setValue("Rss/qt5/splitter_v", state);
setValue("Rss/qt5/splitterMain", state);
#else
setValue("Rss/splitter_v", state);
setValue("Rss/splitterMain", state);
#endif
}
QString Preferences::getSearchColsWidth() const
QByteArray Preferences::getSearchTabHeaderState() const
{
return value("SearchResultsColsWidth").toString();
#ifdef QBT_USES_QT5
return value("SearchTab/qt5/HeaderState").toByteArray();
#else
return value("SearchTab/HeaderState").toByteArray();
#endif
}
void Preferences::setSearchColsWidth(const QString &width)
void Preferences::setSearchTabHeaderState(const QByteArray &state)
{
setValue("SearchResultsColsWidth", width);
#ifdef QBT_USES_QT5
setValue("SearchTab/qt5/HeaderState", state);
#else
setValue("SearchTab/HeaderState", state);
#endif
}
QStringList Preferences::getSearchEngDisabled() const

View File

@@ -57,18 +57,6 @@ enum scheduler_days
SUN
};
namespace Proxy
{
enum ProxyType
{
HTTP = 1,
SOCKS5 = 2,
HTTP_PW = 3,
SOCKS5_PW = 4,
SOCKS4 = 5
};
}
namespace TrayIcon
{
enum Style
@@ -102,7 +90,6 @@ class Preferences: public QObject
void setValue(const QString &key, const QVariant &value);
static Preferences* m_instance;
int m_randomPort;
signals:
void changed();
@@ -127,8 +114,6 @@ public:
void setHideZeroValues(bool b);
int getHideZeroComboValues() const;
void setHideZeroComboValues(int n);
bool useRandomPort() const;
void setRandomPort(bool b);
bool systrayIntegration() const;
void setSystrayIntegration(bool enabled);
bool isToolbarDisplayed() const;
@@ -149,22 +134,12 @@ public:
#endif
// Downloads
bool useIncompleteFilesExtension() const;
void useIncompleteFilesExtension(bool enabled);
QString lastLocationPath() const;
void setLastLocationPath(const QString &path);
bool preAllocateAllFiles() const;
void preAllocateAllFiles(bool enabled);
QVariantHash getScanDirs() const;
void setScanDirs(const QVariantHash &dirs);
QString getScanDirsLastPath() const;
void setScanDirsLastPath(const QString &path);
bool isTorrentExportEnabled() const;
QString getTorrentExportDir() const;
void setTorrentExportDir(QString path);
bool isFinishedTorrentExportEnabled() const;
QString getFinishedTorrentExportDir() const;
void setFinishedTorrentExportDir(QString path);
bool isMailNotificationEnabled() const;
void setMailNotificationEnabled(bool enabled);
QString getMailNotificationEmail() const;
@@ -185,22 +160,6 @@ public:
void setActionOnDblClOnTorrentFn(int act);
// Connection options
int getSessionPort() const;
void setSessionPort(int port);
bool isUPnPEnabled() const;
void setUPnPEnabled(bool enabled);
int getGlobalDownloadLimit() const;
void setGlobalDownloadLimit(int limit);
int getGlobalUploadLimit() const;
void setGlobalUploadLimit(int limit);
int getAltGlobalDownloadLimit() const;
void setAltGlobalDownloadLimit(int limit);
int getAltGlobalUploadLimit() const;
void setAltGlobalUploadLimit(int limit);
bool isAltBandwidthEnabled() const;
void setAltBandwidthEnabled(bool enabled);
bool isSchedulerEnabled() const;
void setSchedulerEnabled(bool enabled);
QTime getSchedulerStartTime() const;
void setSchedulerStartTime(const QTime &time);
QTime getSchedulerEndTime() const;
@@ -208,80 +167,10 @@ public:
scheduler_days getSchedulerDays() const;
void setSchedulerDays(scheduler_days days);
// Proxy options
bool isProxyEnabled() const;
bool isProxyAuthEnabled() const;
void setProxyAuthEnabled(bool enabled);
QString getProxyIp() const;
void setProxyIp(const QString &ip);
unsigned short getProxyPort() const;
void setProxyPort(unsigned short port);
QString getProxyUsername() const;
void setProxyUsername(const QString &username);
QString getProxyPassword() const;
void setProxyPassword(const QString &password);
int getProxyType() const;
void setProxyType(int type);
bool proxyPeerConnections() const;
void setProxyPeerConnections(bool enabled);
bool getForceProxy() const;
void setForceProxy(bool enabled);
void setProxyOnlyForTorrents(bool enabled);
bool isProxyOnlyForTorrents() const;
// Bittorrent options
int getMaxConnecs() const;
void setMaxConnecs(int val);
int getMaxConnecsPerTorrent() const;
void setMaxConnecsPerTorrent(int val);
int getMaxUploads() const;
void setMaxUploads(int val);
int getMaxUploadsPerTorrent() const;
void setMaxUploadsPerTorrent(int val);
bool isuTPEnabled() const;
void setuTPEnabled(bool enabled);
bool isuTPRateLimited() const;
void setuTPRateLimited(bool enabled);
bool isDHTEnabled() const;
void setDHTEnabled(bool enabled);
bool isPeXEnabled() const;
void setPeXEnabled(bool enabled);
bool isLSDEnabled() const;
void setLSDEnabled(bool enabled);
int getEncryptionSetting() const;
void setEncryptionSetting(int val);
bool isAddTrackersEnabled() const;
void setAddTrackersEnabled(bool enabled);
QString getTrackersList() const;
void setTrackersList(const QString &val);
qreal getGlobalMaxRatio() const;
void setGlobalMaxRatio(qreal ratio);
// IP Filter
bool isFilteringEnabled() const;
void setFilteringEnabled(bool enabled);
bool isFilteringTrackerEnabled() const;
void setFilteringTrackerEnabled(bool enabled);
QString getFilter() const;
void setFilter(const QString &path);
QStringList bannedIPs() const;
void banIP(const QString &ip);
// Search
bool isSearchEnabled() const;
void setSearchEnabled(bool enabled);
// Queueing system
bool isQueueingSystemEnabled() const;
void setQueueingSystemEnabled(bool enabled);
int getMaxActiveDownloads() const;
void setMaxActiveDownloads(int val);
int getMaxActiveUploads() const;
void setMaxActiveUploads(int val);
int getMaxActiveTorrents() const;
void setMaxActiveTorrents(int val);
bool ignoreSlowTorrentsForQueueing() const;
void setIgnoreSlowTorrentsForQueueing(bool ignore);
bool isWebUiEnabled() const;
void setWebUiEnabled(bool enabled);
bool isWebUiLocalAuthEnabled() const;
@@ -331,50 +220,12 @@ public:
void setShutdownqBTWhenDownloadsComplete(bool shutdown);
bool dontConfirmAutoExit() const;
void setDontConfirmAutoExit(bool dontConfirmAutoExit);
uint diskCacheSize() const;
void setDiskCacheSize(uint size);
uint diskCacheTTL() const;
void setDiskCacheTTL(uint ttl);
bool osCache() const;
void setOsCache(bool enable);
uint saveResumeDataInterval() const;
void setSaveResumeDataInterval(uint m);
uint outgoingPortsMin() const;
void setOutgoingPortsMin(uint val);
uint outgoingPortsMax() const;
void setOutgoingPortsMax(uint val);
bool getIgnoreLimitsOnLAN() const;
void setIgnoreLimitsOnLAN(bool ignore);
bool includeOverheadInLimits() const;
void includeOverheadInLimits(bool include);
bool trackerExchangeEnabled() const;
void setTrackerExchangeEnabled(bool enable);
bool recheckTorrentsOnCompletion() const;
void recheckTorrentsOnCompletion(bool recheck);
unsigned int getRefreshInterval() const;
void setRefreshInterval(uint interval);
bool resolvePeerCountries() const;
void resolvePeerCountries(bool resolve);
bool resolvePeerHostNames() const;
void resolvePeerHostNames(bool resolve);
int getMaxHalfOpenConnections() const;
void setMaxHalfOpenConnections(int value);
QString getNetworkInterface() const;
void setNetworkInterface(const QString& iface);
QString getNetworkInterfaceName() const;
void setNetworkInterfaceName(const QString& iface);
QString getNetworkInterfaceAddress() const;
void setNetworkInterfaceAddress(const QString& addr);
bool getListenIPv6() const;
void setListenIPv6(bool enable);
QString getNetworkAddress() const;
void setNetworkAddress(const QString& addr);
bool isAnonymousModeEnabled() const;
void enableAnonymousMode(bool enabled);
bool isSuperSeedingEnabled() const;
void enableSuperSeeding(bool enabled);
bool announceToAllTrackers() const;
void setAnnounceToAllTrackers(bool enabled);
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
bool useSystemIconTheme() const;
void useSystemIconTheme(bool enabled);
@@ -396,8 +247,6 @@ public:
static void setTorrentFileAssoc();
static void setMagnetLinkAssoc();
#endif
bool isTrackerEnabled() const;
void setTrackerEnabled(bool enabled);
int getTrackerPort() const;
void setTrackerPort(int port);
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
@@ -451,12 +300,12 @@ public:
void setRssHSplitterSizes(const QByteArray &sizes);
QStringList getRssOpenFolders() const;
void setRssOpenFolders(const QStringList &folders);
QByteArray getRssHSplitterState() const;
void setRssHSplitterState(const QByteArray &state);
QByteArray getRssVSplitterState() const;
void setRssVSplitterState(const QByteArray &state);
QString getSearchColsWidth() const;
void setSearchColsWidth(const QString &width);
QByteArray getRssSideSplitterState() const;
void setRssSideSplitterState(const QByteArray &state);
QByteArray getRssMainSplitterState() const;
void setRssMainSplitterState(const QByteArray &state);
QByteArray getSearchTabHeaderState() const;
void setSearchTabHeaderState(const QByteArray &state);
QStringList getSearchEngDisabled() const;
void setSearchEngDisabled(const QStringList &engines);
QString getCreateTorLastAddPath() const;

View File

@@ -39,7 +39,7 @@ class QIniSettings : public QSettings {
public:
QIniSettings(const QString &organization = "qBittorrent", const QString &application = "qBittorrent", QObject *parent = 0 ):
#ifdef Q_OS_WIN
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
QSettings(QSettings::IniFormat, QSettings::UserScope, organization, application, parent)
#else
QSettings(organization, application, parent)

View File

@@ -31,6 +31,8 @@
#include <QRegExp>
#include <QDebug>
#include <QDir>
#include <QString>
#include <QStringList>
#include "base/preferences.h"
#include "base/utils/fs.h"
@@ -48,53 +50,122 @@ DownloadRule::DownloadRule()
{
}
bool DownloadRule::matches(const QString &articleTitle, const QString &expression) const
{
static QRegExp whitespace("\\s+");
if (expression.isEmpty()) {
// A regex of the form "expr|" will always match, so do the same for wildcards
return true;
}
else if (m_useRegex) {
QRegExp reg(expression, Qt::CaseInsensitive, QRegExp::RegExp);
return reg.indexIn(articleTitle) > -1;
}
else {
// Only match if every wildcard token (separated by spaces) is present in the article name.
// Order of wildcard tokens is unimportant (if order is important, they should have used *).
foreach (const QString &wildcard, expression.split(whitespace, QString::SplitBehavior::SkipEmptyParts)) {
QRegExp reg(wildcard, Qt::CaseInsensitive, QRegExp::Wildcard);
if (reg.indexIn(articleTitle) == -1)
return false;
}
}
return true;
}
bool DownloadRule::matches(const QString &articleTitle) const
{
foreach (const QString &token, m_mustContain) {
if (!token.isEmpty()) {
QRegExp reg(token, Qt::CaseInsensitive, m_useRegex ? QRegExp::RegExp : QRegExp::Wildcard);
if (reg.indexIn(articleTitle) < 0)
return false;
}
}
qDebug("Checking not matching tokens");
// Checking not matching
foreach (const QString &token, m_mustNotContain) {
if (!token.isEmpty()) {
QRegExp reg(token, Qt::CaseInsensitive, m_useRegex ? QRegExp::RegExp : QRegExp::Wildcard);
if (reg.indexIn(articleTitle) > -1)
if (!m_mustContain.empty()) {
bool logged = false;
bool foundMustContain = false;
// Each expression is either a regex, or a set of wildcards separated by whitespace.
// Accept if any complete expression matches.
foreach (const QString &expression, m_mustContain) {
if (!logged) {
qDebug() << "Checking matching" << (m_useRegex ? "regex:" : "wildcard expressions:") << m_mustContain.join("|");
logged = true;
}
// A regex of the form "expr|" will always match, so do the same for wildcards
foundMustContain = matches(articleTitle, expression);
if (foundMustContain) {
qDebug() << "Found matching" << (m_useRegex ? "regex:" : "wildcard expression:") << expression;
break;
}
}
if (!foundMustContain)
return false;
}
if (!m_mustNotContain.empty()) {
bool logged = false;
// Each expression is either a regex, or a set of wildcards separated by whitespace.
// Reject if any complete expression matches.
foreach (const QString &expression, m_mustNotContain) {
if (!logged) {
qDebug() << "Checking not matching" << (m_useRegex ? "regex:" : "wildcard expressions:") << m_mustNotContain.join("|");
logged = true;
}
// A regex of the form "expr|" will always match, so do the same for wildcards
if (matches(articleTitle, expression)) {
qDebug() << "Found not matching" << (m_useRegex ? "regex:" : "wildcard expression:") << expression;
return false;
}
}
}
if (!m_episodeFilter.isEmpty()) {
qDebug("Checking episode filter");
qDebug() << "Checking episode filter:" << m_episodeFilter;
QRegExp f("(^\\d{1,4})x(.*;$)");
int pos = f.indexIn(m_episodeFilter);
if (pos < 0)
return false;
QString s = f.cap(1);
QStringList eps = f.cap(2).split(";");
QString expStr;
expStr += "s0?" + s + "[ -_\\.]?" + "e0?";
int sOurs = s.toInt();
foreach (const QString &ep, eps) {
foreach (QString ep, eps) {
if (ep.isEmpty())
continue;
// We need to trim leading zeroes, but if it's all zeros then we want episode zero.
while (ep.size() > 1 && ep.startsWith("0"))
ep = ep.right(ep.size() - 1);
if (ep.indexOf('-') != -1) { // Range detected
QString partialPattern = "s0?" + s + "[ -_\\.]?" + "e(0?\\d{1,4})";
QRegExp reg(partialPattern, Qt::CaseInsensitive);
QString partialPattern1 = "\\bs0?(\\d{1,4})[ -_\\.]?e(0?\\d{1,4})(?:\\D|\\b)";
QString partialPattern2 = "\\b(\\d{1,4})x(0?\\d{1,4})(?:\\D|\\b)";
QRegExp reg(partialPattern1, Qt::CaseInsensitive);
if (ep.endsWith('-')) { // Infinite range
int epOurs = ep.left(ep.size() - 1).toInt();
// Extract partial match from article and compare as digits
pos = reg.indexIn(articleTitle);
if (pos == -1) {
reg = QRegExp(partialPattern2, Qt::CaseInsensitive);
pos = reg.indexIn(articleTitle);
}
if (pos != -1) {
int epTheirs = reg.cap(1).toInt();
if (epTheirs >= epOurs)
int sTheirs = reg.cap(1).toInt();
int epTheirs = reg.cap(2).toInt();
if (((sTheirs == sOurs) && (epTheirs >= epOurs)) || (sTheirs > sOurs)) {
qDebug() << "Matched episode:" << ep;
qDebug() << "Matched article:" << articleTitle;
return true;
}
}
}
else { // Normal range
@@ -108,21 +179,38 @@ bool DownloadRule::matches(const QString &articleTitle) const
// Extract partial match from article and compare as digits
pos = reg.indexIn(articleTitle);
if (pos == -1) {
reg = QRegExp(partialPattern2, Qt::CaseInsensitive);
pos = reg.indexIn(articleTitle);
}
if (pos != -1) {
int epTheirs = reg.cap(1).toInt();
if (epOursFirst <= epTheirs && epOursLast >= epTheirs)
int sTheirs = reg.cap(1).toInt();
int epTheirs = reg.cap(2).toInt();
if ((sTheirs == sOurs) && ((epOursFirst <= epTheirs) && (epOursLast >= epTheirs))) {
qDebug() << "Matched episode:" << ep;
qDebug() << "Matched article:" << articleTitle;
return true;
}
}
}
}
else { // Single number
QRegExp reg(expStr + ep + "\\D", Qt::CaseInsensitive);
if (reg.indexIn(articleTitle) != -1)
QString expStr("\\b(?:s0?" + s + "[ -_\\.]?" + "e0?" + ep + "|" + s + "x" + "0?" + ep + ")(?:\\D|\\b)");
QRegExp reg(expStr, Qt::CaseInsensitive);
if (reg.indexIn(articleTitle) != -1) {
qDebug() << "Matched episode:" << ep;
qDebug() << "Matched article:" << articleTitle;
return true;
}
}
}
return false;
}
qDebug() << "Matched article:" << articleTitle;
return true;
}
@@ -131,7 +219,11 @@ void DownloadRule::setMustContain(const QString &tokens)
if (m_useRegex)
m_mustContain = QStringList() << tokens;
else
m_mustContain = tokens.split(" ");
m_mustContain = tokens.split("|");
// Check for single empty string - if so, no condition
if ((m_mustContain.size() == 1) && m_mustContain[0].isEmpty())
m_mustContain.clear();
}
void DownloadRule::setMustNotContain(const QString &tokens)
@@ -140,6 +232,10 @@ void DownloadRule::setMustNotContain(const QString &tokens)
m_mustNotContain = QStringList() << tokens;
else
m_mustNotContain = tokens.split("|");
// Check for single empty string - if so, no condition
if ((m_mustNotContain.size() == 1) && m_mustNotContain[0].isEmpty())
m_mustNotContain.clear();
}
QStringList DownloadRule::rssFeeds() const
@@ -189,7 +285,7 @@ QVariantHash DownloadRule::toVariantHash() const
{
QVariantHash hash;
hash["name"] = m_name;
hash["must_contain"] = m_mustContain.join(" ");
hash["must_contain"] = m_mustContain.join("|");
hash["must_not_contain"] = m_mustNotContain.join("|");
hash["save_path"] = m_savePath;
hash["affected_feeds"] = m_rssFeeds;
@@ -265,7 +361,7 @@ int DownloadRule::ignoreDays() const
QString DownloadRule::mustContain() const
{
return m_mustContain.join(" ");
return m_mustContain.join("|");
}
QString DownloadRule::mustNotContain() const
@@ -300,8 +396,9 @@ QStringList DownloadRule::findMatchingArticles(const FeedPtr &feed) const
ArticleHash::ConstIterator artIt = feedArticles.begin();
ArticleHash::ConstIterator artItend = feedArticles.end();
for ( ; artIt != artItend ; ++artIt) {
for (; artIt != artItend; ++artIt) {
const QString title = artIt.value()->title();
qDebug() << "Matching article:" << title;
if (matches(title))
ret << title;
}

View File

@@ -88,6 +88,8 @@ namespace Rss
bool operator==(const DownloadRule &other) const;
private:
bool matches(const QString &articleTitle, const QString &expression) const;
QString m_name;
QStringList m_mustContain;
QStringList m_mustNotContain;

View File

@@ -46,6 +46,7 @@ DownloadRuleList::DownloadRuleList()
DownloadRulePtr DownloadRuleList::findMatchingRule(const QString &feedUrl, const QString &articleTitle) const
{
Q_ASSERT(Preferences::instance()->isRssDownloadingEnabled());
qDebug() << "Matching article:" << articleTitle;
QStringList ruleNames = m_feedRules.value(feedUrl);
foreach (const QString &rule_name, ruleNames) {
DownloadRulePtr rule = m_rules[rule_name];

View File

@@ -78,7 +78,7 @@ Feed::Feed(const QString &url, Manager *manager)
// Download the RSS Feed icon
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(iconUrl(), true);
connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(handleIconDownloadFinished(QString, QString)));
connect(handler, SIGNAL(downloadFinished(QString,QString)), this, SLOT(handleIconDownloadFinished(QString,QString)));
// Load old RSS articles
loadItemsFromDisk();
@@ -99,24 +99,24 @@ void Feed::saveItemsToDisk()
m_dirty = false;
QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss");
QIniSettings qBTRSSFeeds("qBittorrent", "qBittorrent-rss-feeds");
QVariantList oldItems;
ArticleHash::ConstIterator it = m_articles.begin();
ArticleHash::ConstIterator itend = m_articles.end();
for ( ; it != itend; ++it) {
for (; it != itend; ++it)
oldItems << it.value()->toHash();
}
qDebug("Saving %d old items for feed %s", oldItems.size(), qPrintable(displayName()));
QHash<QString, QVariant> allOldItems = qBTRSS.value("old_items", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> allOldItems = qBTRSSFeeds.value("old_items", QHash<QString, QVariant>()).toHash();
allOldItems[m_url] = oldItems;
qBTRSS.setValue("old_items", allOldItems);
qBTRSSFeeds.setValue("old_items", allOldItems);
}
void Feed::loadItemsFromDisk()
{
QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss");
QHash<QString, QVariant> allOldItems = qBTRSS.value("old_items", QHash<QString, QVariant>()).toHash();
QIniSettings qBTRSSFeeds("qBittorrent", "qBittorrent-rss-feeds");
QHash<QString, QVariant> allOldItems = qBTRSSFeeds.value("old_items", QHash<QString, QVariant>()).toHash();
const QVariantList oldItems = allOldItems.value(m_url, QVariantList()).toList();
qDebug("Loading %d old items for feed %s", oldItems.size(), qPrintable(displayName()));
@@ -155,20 +155,18 @@ void Feed::addArticle(const ArticlePtr &article)
}
// Check if article was inserted at the end of the list and will break max_articles limit
if (Preferences::instance()->isRssDownloadingEnabled()) {
if (Preferences::instance()->isRssDownloadingEnabled())
if ((lbIndex < maxArticles) && !article->isRead())
downloadArticleTorrentIfMatching(article);
}
}
else {
// m_articles.contains(article->guid())
// Try to download skipped articles
if (Preferences::instance()->isRssDownloadingEnabled()) {
ArticlePtr skipped = m_articles.value(article->guid(), ArticlePtr());
if (skipped) {
if (skipped)
if (!skipped->isRead())
downloadArticleTorrentIfMatching(skipped);
}
}
}
}
@@ -182,8 +180,8 @@ bool Feed::refresh()
m_loading = true;
// Download the RSS again
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(m_url);
connect(handler, SIGNAL(downloadFinished(QString, QByteArray)), this, SLOT(handleRssDownloadFinished(QString, QByteArray)));
connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(handleRssDownloadFailed(QString, QString)));
connect(handler, SIGNAL(downloadFinished(QString,QByteArray)), this, SLOT(handleRssDownloadFinished(QString,QByteArray)));
connect(handler, SIGNAL(downloadFailed(QString,QString)), this, SLOT(handleRssDownloadFailed(QString,QString)));
return true;
}
@@ -206,10 +204,11 @@ void Feed::removeAllSettings()
allFeedsFilters.remove(m_url);
qBTRSS.setValue("feed_filters", allFeedsFilters);
}
QVariantHash allOldItems = qBTRSS.value("old_items", QVariantHash()).toHash();
QIniSettings qBTRSSFeeds("qBittorrent", "qBittorrent-rss-feeds");
QVariantHash allOldItems = qBTRSSFeeds.value("old_items", QVariantHash()).toHash();
if (allOldItems.contains(m_url)) {
allOldItems.remove(m_url);
qBTRSS.setValue("old_items", allOldItems);
qBTRSSFeeds.setValue("old_items", allOldItems);
}
}
@@ -259,8 +258,13 @@ bool Feed::hasCustomIcon() const
void Feed::setIconPath(const QString &path)
{
if (!path.isEmpty() && QFile::exists(path))
m_icon = path;
QString nativePath = Utils::Fs::fromNativePath(path);
if ((nativePath == m_icon) || nativePath.isEmpty() || !QFile::exists(nativePath)) return;
if (!m_icon.startsWith(":/") && QFile::exists(m_icon))
Utils::Fs::forceRemove(m_icon);
m_icon = nativePath;
}
ArticlePtr Feed::getItem(const QString &guid) const
@@ -277,9 +281,8 @@ void Feed::markAsRead()
{
ArticleHash::ConstIterator it = m_articles.begin();
ArticleHash::ConstIterator itend = m_articles.end();
for ( ; it != itend; ++it) {
for (; it != itend; ++it)
it.value()->markAsRead();
}
m_unreadCount = 0;
m_manager->forwardFeedInfosChanged(m_url, displayName(), 0);
}
@@ -305,10 +308,9 @@ ArticleList Feed::unreadArticleListByDateDesc() const
ArticleList::ConstIterator it = m_articlesByDate.begin();
ArticleList::ConstIterator itend = m_articlesByDate.end();
for ( ; it != itend; ++it) {
for (; it != itend; ++it)
if (!(*it)->isRead())
unreadNews << *it;
}
return unreadNews;
}
@@ -322,7 +324,7 @@ QString Feed::iconUrl() const
void Feed::handleIconDownloadFinished(const QString &url, const QString &filePath)
{
Q_UNUSED(url);
m_icon = filePath;
setIconPath(filePath);
qDebug() << Q_FUNC_INFO << "icon path:" << m_icon;
m_manager->forwardFeedIconChanged(m_url, m_icon);
}
@@ -359,6 +361,14 @@ void Feed::handleFeedTitle(const QString &title)
void Feed::downloadArticleTorrentIfMatching(const ArticlePtr &article)
{
Q_ASSERT(Preferences::instance()->isRssDownloadingEnabled());
qDebug().nospace() << Q_FUNC_INFO << " Deferring matching of " << article->title() << " from " << displayName() << " RSS feed";
m_manager->downloadArticleTorrentIfMatching(m_url, article);
}
void Feed::deferredDownloadArticleTorrentIfMatching(const ArticlePtr &article)
{
qDebug().nospace() << Q_FUNC_INFO << " Matching of " << article->title() << " from " << displayName() << " RSS feed";
DownloadRuleList *rules = m_manager->downloadRules();
DownloadRulePtr matchingRule = rules->findMatchingRule(m_url, article->title());
if (!matchingRule) return;
@@ -402,10 +412,9 @@ void Feed::downloadArticleTorrentIfMatching(const ArticlePtr &article)
void Feed::recheckRssItemsForDownload()
{
Q_ASSERT(Preferences::instance()->isRssDownloadingEnabled());
foreach (const ArticlePtr &article, m_articlesByDate) {
foreach (const ArticlePtr &article, m_articlesByDate)
if (!article->isRead())
downloadArticleTorrentIfMatching(article);
}
}
void Feed::handleNewArticle(const QVariantHash &articleData)
@@ -421,7 +430,7 @@ void Feed::handleNewArticle(const QVariantHash &articleData)
m_manager->forwardFeedInfosChanged(m_url, displayName(), m_unreadCount);
// FIXME: We should forward the information here but this would seriously decrease
// performance with current design.
//m_manager->forwardFeedContentChanged(m_url);
// m_manager->forwardFeedContentChanged(m_url);
}
void Feed::handleParsingFinished(const QString &error)

View File

@@ -64,7 +64,7 @@ namespace Rss
Q_OBJECT
public:
Feed(const QString &url, Manager *manager);
Feed(const QString &url, Manager * manager);
~Feed();
bool refresh();
@@ -98,10 +98,13 @@ namespace Rss
void handleArticleRead();
private:
friend class Manager;
QString iconUrl() const;
void loadItemsFromDisk();
void addArticle(const ArticlePtr &article);
void downloadArticleTorrentIfMatching(const ArticlePtr &article);
void deferredDownloadArticleTorrentIfMatching(const ArticlePtr &article);
private:
Manager *m_manager;

View File

@@ -54,6 +54,10 @@ Manager::Manager(QObject *parent)
connect(&m_refreshTimer, SIGNAL(timeout()), SLOT(refresh()));
m_refreshInterval = Preferences::instance()->getRSSRefreshInterval();
m_refreshTimer.start(m_refreshInterval * MSECS_PER_MIN);
m_deferredDownloadTimer.setInterval(1);
m_deferredDownloadTimer.setSingleShot(true);
connect(&m_deferredDownloadTimer, SIGNAL(timeout()), SLOT(downloadNextArticleTorrentIfMatching()));
}
Manager::~Manager()
@@ -72,7 +76,7 @@ void Manager::updateRefreshInterval(uint val)
{
if (m_refreshInterval != val) {
m_refreshInterval = val;
m_refreshTimer.start(m_refreshInterval*60000);
m_refreshTimer.start(m_refreshInterval * 60000);
qDebug("New RSS refresh interval is now every %dmin", m_refreshInterval);
}
}
@@ -81,7 +85,7 @@ void Manager::loadStreamList()
{
const Preferences *const pref = Preferences::instance();
const QStringList streamsUrl = pref->getRssFeedsUrls();
const QStringList aliases = pref->getRssFeedsAliases();
const QStringList aliases = pref->getRssFeedsAliases();
if (streamsUrl.size() != aliases.size()) {
Logger::instance()->addMessage("Corrupted RSS list, not loading it.", Log::WARNING);
return;
@@ -188,3 +192,27 @@ void Manager::refresh()
{
m_rootFolder->refresh();
}
void Manager::downloadArticleTorrentIfMatching(const QString &url, const ArticlePtr &article)
{
m_deferredDownloads.append(qMakePair(url, article));
m_deferredDownloadTimer.start();
}
void Manager::downloadNextArticleTorrentIfMatching()
{
if (m_deferredDownloads.empty())
return;
// Schedule to process the next article (if any)
m_deferredDownloadTimer.start();
QPair<QString, ArticlePtr> urlArticle(m_deferredDownloads.takeFirst());
FeedList streams = m_rootFolder->getAllFeeds();
foreach (const FeedPtr &stream, streams) {
if (stream->url() == urlArticle.first) {
stream->deferredDownloadArticleTorrentIfMatching(urlArticle.second);
break;
}
}
}

View File

@@ -32,19 +32,23 @@
#ifndef RSSMANAGER_H
#define RSSMANAGER_H
#include <QList>
#include <QObject>
#include <QPair>
#include <QTimer>
#include <QSharedPointer>
#include <QThread>
namespace Rss
{
class Article;
class DownloadRuleList;
class File;
class Folder;
class Feed;
class Manager;
typedef QSharedPointer<Article> ArticlePtr;
typedef QSharedPointer<File> FilePtr;
typedef QSharedPointer<Folder> FolderPtr;
typedef QSharedPointer<Feed> FeedPtr;
@@ -62,6 +66,7 @@ namespace Rss
DownloadRuleList *downloadRules() const;
FolderPtr rootFolder() const;
QThread *workingThread() const;
void downloadArticleTorrentIfMatching(const QString &url, const ArticlePtr &article);
public slots:
void refresh();
@@ -78,12 +83,17 @@ namespace Rss
void feedInfosChanged(const QString &url, const QString &displayName, uint unreadCount);
void feedIconChanged(const QString &url, const QString &iconPath);
private slots:
void downloadNextArticleTorrentIfMatching();
private:
QTimer m_refreshTimer;
uint m_refreshInterval;
DownloadRuleList *m_downloadRules;
FolderPtr m_rootFolder;
QThread *m_workingThread;
QTimer m_deferredDownloadTimer;
QList<QPair<QString, ArticlePtr>> m_deferredDownloads;
};
}

View File

@@ -62,7 +62,7 @@ static inline void removePythonScriptIfExists(const QString &scriptPath)
const QHash<QString, QString> SearchEngine::m_categoryNames = SearchEngine::initializeCategoryNames();
SearchEngine::SearchEngine()
: m_updateUrl(QString("https://raw.github.com/qbittorrent/qBittorrent/master/src/searchengine/%1/engines/").arg(Utils::Misc::pythonVersion() >= 3 ? "nova3" : "nova"))
: m_updateUrl(QString("http://searchplugins.qbittorrent.org/%1/engines/").arg(Utils::Misc::pythonVersion() >= 3 ? "nova3" : "nova"))
, m_searchStopped(false)
{
updateNova();

View File

@@ -38,10 +38,6 @@
#include "logger.h"
#include "utils/fs.h"
#ifdef Q_OS_MAC
#define QSETTINGS_SYNC_IS_SAVE // whether QSettings::sync() is "atomic"
#endif
namespace
{
// Encapsulates serialization of settings in "atomic" way.
@@ -69,7 +65,7 @@ namespace
using SettingsPtr = std::unique_ptr<QSettings>;
SettingsPtr createSettings(const QString &name)
{
#ifdef Q_OS_WIN
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
return SettingsPtr(new QSettings(QSettings::IniFormat, QSettings::UserScope, "qBittorrent", name));
#else
return SettingsPtr(new QSettings("qBittorrent", name));
@@ -98,22 +94,86 @@ namespace
{
static const MappingTable keyMapping = {
{ "BitTorrent/Session/MaxRatioAction", "Preferences/Bittorrent/MaxRatioAction" },
{ "BitTorrent/Session/DefaultSavePath", "Preferences/Downloads/SavePath" },
{ "BitTorrent/Session/TempPath", "Preferences/Downloads/TempPath" },
{ "BitTorrent/Session/TempPathEnabled", "Preferences/Downloads/TempPathEnabled" },
{ "BitTorrent/Session/AddTorrentPaused", "Preferences/Downloads/StartInPause" },
{"BitTorrent/Session/MaxRatioAction", "Preferences/Bittorrent/MaxRatioAction"},
{"BitTorrent/Session/DefaultSavePath", "Preferences/Downloads/SavePath"},
{"BitTorrent/Session/TempPath", "Preferences/Downloads/TempPath"},
{"BitTorrent/Session/TempPathEnabled", "Preferences/Downloads/TempPathEnabled"},
{"BitTorrent/Session/AddTorrentPaused", "Preferences/Downloads/StartInPause"},
{"BitTorrent/Session/RefreshInterval", "Preferences/General/RefreshInterval"},
{"BitTorrent/Session/Preallocation", "Preferences/Downloads/PreAllocation"},
{"BitTorrent/Session/AddExtensionToIncompleteFiles", "Preferences/Downloads/UseIncompleteExtension"},
{"BitTorrent/Session/TorrentExportDirectory", "Preferences/Downloads/TorrentExportDir"},
{"BitTorrent/Session/FinishedTorrentExportDirectory", "Preferences/Downloads/FinishedTorrentExportDir"},
{"BitTorrent/Session/GlobalUPSpeedLimit", "Preferences/Connection/GlobalUPLimit"},
{"BitTorrent/Session/GlobalDLSpeedLimit", "Preferences/Connection/GlobalDLLimit"},
{"BitTorrent/Session/AlternativeGlobalUPSpeedLimit", "Preferences/Connection/GlobalUPLimitAlt"},
{"BitTorrent/Session/AlternativeGlobalDLSpeedLimit", "Preferences/Connection/GlobalDLLimitAlt"},
{"BitTorrent/Session/UseAlternativeGlobalSpeedLimit", "Preferences/Connection/alt_speeds_on"},
{"BitTorrent/Session/BandwidthSchedulerEnabled", "Preferences/Scheduler/Enabled"},
{"BitTorrent/Session/Port", "Preferences/Connection/PortRangeMin"},
{"BitTorrent/Session/UseRandomPort", "Preferences/General/UseRandomPort"},
{"BitTorrent/Session/IPv6Enabled", "Preferences/Connection/InterfaceListenIPv6"},
{"BitTorrent/Session/Interface", "Preferences/Connection/Interface"},
{"BitTorrent/Session/InterfaceName", "Preferences/Connection/InterfaceName"},
{"BitTorrent/Session/InterfaceAddress", "Preferences/Connection/InterfaceAddress"},
{"BitTorrent/Session/SaveResumeDataInterval", "Preferences/Downloads/SaveResumeDataInterval"},
{"BitTorrent/Session/Encryption", "Preferences/Bittorrent/Encryption"},
{"BitTorrent/Session/ForceProxy", "Preferences/Connection/ProxyForce"},
{"BitTorrent/Session/ProxyPeerConnections", "Preferences/Connection/ProxyPeerConnections"},
{"BitTorrent/Session/MaxConnections", "Preferences/Bittorrent/MaxConnecs"},
{"BitTorrent/Session/MaxUploads", "Preferences/Bittorrent/MaxUploads"},
{"BitTorrent/Session/MaxConnectionsPerTorrent", "Preferences/Bittorrent/MaxConnecsPerTorrent"},
{"BitTorrent/Session/MaxUploadsPerTorrent", "Preferences/Bittorrent/MaxUploadsPerTorrent"},
{"BitTorrent/Session/DHTEnabled", "Preferences/Bittorrent/DHT"},
{"BitTorrent/Session/LSDEnabled", "Preferences/Bittorrent/LSD"},
{"BitTorrent/Session/PeXEnabled", "Preferences/Bittorrent/PeX"},
{"BitTorrent/Session/AddTrackersEnabled", "Preferences/Bittorrent/AddTrackers"},
{"BitTorrent/Session/AdditionalTrackers", "Preferences/Bittorrent/TrackersList"},
{"BitTorrent/Session/IPFilteringEnabled", "Preferences/IPFilter/Enabled"},
{"BitTorrent/Session/TrackerFilteringEnabled", "Preferences/IPFilter/FilterTracker"},
{"BitTorrent/Session/IPFilter", "Preferences/IPFilter/File"},
{"BitTorrent/Session/GlobalMaxRatio", "Preferences/Bittorrent/MaxRatio"},
{"BitTorrent/Session/AnnounceToAllTrackers", "Preferences/Advanced/AnnounceToAllTrackers"},
{"BitTorrent/Session/DiskCacheSize", "Preferences/Downloads/DiskWriteCacheSize"},
{"BitTorrent/Session/DiskCacheTTL", "Preferences/Downloads/DiskWriteCacheTTL"},
{"BitTorrent/Session/UseOSCache", "Preferences/Advanced/osCache"},
{"BitTorrent/Session/AnonymousModeEnabled", "Preferences/Advanced/AnonymousMode"},
{"BitTorrent/Session/QueueingSystemEnabled", "Preferences/Queueing/QueueingEnabled"},
{"BitTorrent/Session/MaxActiveDownloads", "Preferences/Queueing/MaxActiveDownloads"},
{"BitTorrent/Session/MaxActiveUploads", "Preferences/Queueing/MaxActiveUploads"},
{"BitTorrent/Session/MaxActiveTorrents", "Preferences/Queueing/MaxActiveTorrents"},
{"BitTorrent/Session/IgnoreSlowTorrentsForQueueing", "Preferences/Queueing/IgnoreSlowTorrents"},
{"BitTorrent/Session/OutgoingPortsMin", "Preferences/Advanced/OutgoingPortsMin"},
{"BitTorrent/Session/OutgoingPortsMax", "Preferences/Advanced/OutgoingPortsMax"},
{"BitTorrent/Session/IgnoreLimitsOnLAN", "Preferences/Advanced/IgnoreLimitsLAN"},
{"BitTorrent/Session/IncludeOverheadInLimits", "Preferences/Advanced/IncludeOverhead"},
{"BitTorrent/Session/AnnounceIP", "Preferences/Connection/InetAddress"},
{"BitTorrent/Session/SuperSeedingEnabled", "Preferences/Advanced/SuperSeeding"},
{"BitTorrent/Session/MaxHalfOpenConnections", "Preferences/Connection/MaxHalfOpenConnec"},
{"BitTorrent/Session/uTPEnabled", "Preferences/Bittorrent/uTP"},
{"BitTorrent/Session/uTPRateLimited", "Preferences/Bittorrent/uTP_rate_limited"},
{"BitTorrent/TrackerEnabled", "Preferences/Advanced/trackerEnabled"},
{"Network/Proxy/OnlyForTorrents", "Preferences/Connection/ProxyOnlyForTorrents"},
{"Network/Proxy/Type", "Preferences/Connection/ProxyType"},
{"Network/Proxy/Authentication", "Preferences/Connection/Proxy/Authentication"},
{"Network/Proxy/Username", "Preferences/Connection/Proxy/Username"},
{"Network/Proxy/Password", "Preferences/Connection/Proxy/Password"},
{"Network/Proxy/IP", "Preferences/Connection/Proxy/IP"},
{"Network/Proxy/Port", "Preferences/Connection/Proxy/Port"},
{"Network/PortForwardingEnabled", "Preferences/Connection/UPnP"},
#ifdef QBT_USES_QT5
{ "AddNewTorrentDialog/TreeHeaderState", "AddNewTorrentDialog/qt5/treeHeaderState" },
{"AddNewTorrentDialog/TreeHeaderState", "AddNewTorrentDialog/qt5/treeHeaderState"},
#else
{ "AddNewTorrentDialog/TreeHeaderState", "AddNewTorrentDialog/treeHeaderState" },
{"AddNewTorrentDialog/TreeHeaderState", "AddNewTorrentDialog/treeHeaderState"},
#endif
{ "AddNewTorrentDialog/Width", "AddNewTorrentDialog/width" },
{ "AddNewTorrentDialog/Position", "AddNewTorrentDialog/y" },
{ "AddNewTorrentDialog/Expanded", "AddNewTorrentDialog/expanded" },
{ "AddNewTorrentDialog/SavePathHistory", "TorrentAdditionDlg/save_path_history" },
{ "AddNewTorrentDialog/Enabled", "Preferences/Downloads/NewAdditionDialog" },
{ "AddNewTorrentDialog/TopLevel", "Preferences/Downloads/NewAdditionDialogFront" }
{"AddNewTorrentDialog/Width", "AddNewTorrentDialog/width"},
{"AddNewTorrentDialog/Position", "AddNewTorrentDialog/y"},
{"AddNewTorrentDialog/Expanded", "AddNewTorrentDialog/expanded"},
{"AddNewTorrentDialog/SavePathHistory", "TorrentAdditionDlg/save_path_history"},
{"AddNewTorrentDialog/Enabled", "Preferences/Downloads/NewAdditionDialog"},
{"AddNewTorrentDialog/TopLevel", "Preferences/Downloads/NewAdditionDialogFront"},
{"State/BannedIPs", "Preferences/IPFilter/BannedIPs"}
};
@@ -201,9 +261,6 @@ void SettingsStorage::removeValue(const QString &key)
QVariantHash TransactionalSettings::read()
{
QVariantHash res;
#ifdef QSETTINGS_SYNC_IS_SAVE
deserialize(m_name, res);
#else
bool writeBackNeeded = false;
QString newPath = deserialize(m_name + QLatin1String("_new"), res);
if (!newPath.isEmpty()) { // "_new" file is NOT empty
@@ -222,15 +279,12 @@ QVariantHash TransactionalSettings::read()
if (writeBackNeeded)
write(res);
#endif
return res;
}
bool TransactionalSettings::write(const QVariantHash &data)
{
#ifdef QSETTINGS_SYNC_IS_SAVE
serialize(m_name, data);
#else
// QSettings delete the file before writing it out. This can result in problems
// if the disk is full or a power outage occurs. Those events might occur
// between deleting the file and recreating it. This is a safety measure.
@@ -247,7 +301,7 @@ bool TransactionalSettings::write(const QVariantHash &data)
finalPath.remove(index, 4);
Utils::Fs::forceRemove(finalPath);
QFile::rename(newPath, finalPath);
#endif
return true;
}

73
src/base/settingvalue.h Normal file
View File

@@ -0,0 +1,73 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#ifndef SETTINGVALUE_H
#define SETTINGVALUE_H
#include <functional>
#include <QString>
#include "settingsstorage.h"
template <typename T>
class CachedSettingValue
{
using ProxyFunc = std::function<T (const T&)>;
public:
explicit CachedSettingValue(const char *keyName, const T &defaultValue = T()
, ProxyFunc proxyFunc = [](const T &value) { return value; })
: m_keyName(QLatin1String(keyName))
, m_value(proxyFunc(SettingsStorage::instance()->loadValue(
m_keyName, defaultValue).template value<T>()))
{
}
T value() const
{
return m_value;
}
CachedSettingValue<T> &operator=(const T &newValue)
{
m_value = newValue;
SettingsStorage::instance()->storeValue(m_keyName, m_value);
return *this;
}
operator T() const
{
return value();
}
private:
const QString m_keyName;
T m_value;
};
#endif // SETTINGVALUE_H

View File

@@ -92,9 +92,11 @@ void TorrentFileGuard::setAutoDeleteMode(TorrentFileGuard::AutoDeleteMode mode)
QMetaEnum TorrentFileGuard::modeMetaEnum()
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
return QMetaEnum::fromType<AutoDeleteMode>();
#else
return staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("AutoDeleteMode"));
const int enumeratorIndex = staticMetaObject.indexOfEnumerator("AutoDeleteMode");
Q_ASSERT(enumeratorIndex >= 0);
return staticMetaObject.enumerator(enumeratorIndex);
#endif
}

View File

@@ -26,6 +26,9 @@
* exception statement from your version.
*/
#ifndef TOFFENTFILEGURAD_H
#define TOFFENTFILEGURAD_H
#include <QString>
#include <QMetaType>
@@ -50,6 +53,10 @@ private:
class TorrentFileGuard
{
Q_GADGET
// moc from Qt4 ignores Q_ENUMS when it is behind #if QT_VERSION check
// this declaration is needed for Qt 4 only
// TODO Qt5: remove when dropping Qt4 support
Q_ENUMS(AutoDeleteMode)
public:
TorrentFileGuard(const QString &path = QString());
@@ -72,9 +79,7 @@ public:
private:
static QMetaEnum modeMetaEnum();
#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
Q_ENUMS(AutoDeleteMode)
#else
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
Q_ENUM(AutoDeleteMode)
#endif
AutoDeleteMode m_mode;
@@ -87,9 +92,12 @@ private:
// This problem is NOT present in Qt 5.7.0 and maybe in some older Qt 5 versions too
// Qt 4.8.7 has it.
// Therefore, we can't inherit FileGuard :(
// TODO Qt5: port to private inheritance when dropping Qt 4 support
FileGuard m_guard;
};
#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
Q_DECLARE_METATYPE(TorrentFileGuard::AutoDeleteMode)
#endif
#endif // TOFFENTFILEGURAD_H

View File

@@ -35,6 +35,7 @@
// we put all problematic UTF-8 chars/strings in this file.
// See issue #3059 for more details (https://github.com/qbittorrent/qBittorrent/issues/3059).
const char C_INFINITY[] = "";
const char C_NON_BREAKING_SPACE[] = " ";
const char C_UP[] = "";
const char C_DOWN[] = "";
const char C_COPYRIGHT[] = "©";
@@ -46,16 +47,20 @@ const char C_LOCALE_ESPERANTO[] = "Esperanto";
const char C_LOCALE_FRENCH[] = "Français";
const char C_LOCALE_GERMAN[] = "Deutsch";
const char C_LOCALE_HUNGARIAN[] = "Magyar";
const char C_LOCALE_ICELANDIC[] = "Íslenska";
const char C_LOCALE_INDONESIAN[] = "Bahasa Indonesia";
const char C_LOCALE_ITALIAN[] = "Italiano";
const char C_LOCALE_DUTCH[] = "Nederlands";
const char C_LOCALE_SPANISH[] = "Español";
const char C_LOCALE_CATALAN[] = "Català";
const char C_LOCALE_GALICIAN[] = "Galego";
const char C_LOCALE_OCCITAN[] = "lenga d'òc";
const char C_LOCALE_PORTUGUESE[] = "Português";
const char C_LOCALE_PORTUGUESE_BRAZIL[] = "Português brasileiro";
const char C_LOCALE_POLISH[] = "Polski";
const char C_LOCALE_LATVIAN[] = "latviešu valoda";
const char C_LOCALE_LITHUANIAN[] = "Lietuvių";
const char C_LOCALE_MALAY[] = "بهاس ملايو";
const char C_LOCALE_CZECH[] = "Čeština";
const char C_LOCALE_SLOVAK[] = "Slovenčina";
const char C_LOCALE_SLOVENIAN[] = "Slovenščina";
@@ -71,6 +76,7 @@ const char C_LOCALE_NORWEGIAN[] = "Norsk";
const char C_LOCALE_DANISH[] = "Dansk";
const char C_LOCALE_BULGARIAN[] = "Български";
const char C_LOCALE_UKRAINIAN[] = "Українська";
const char C_LOCALE_UZBEK[] = "أۇزبېك‎";
const char C_LOCALE_RUSSIAN[] = "Русский";
const char C_LOCALE_JAPANESE[] = "日本語";
const char C_LOCALE_HEBREW[] = "עברית";

View File

@@ -269,67 +269,43 @@ bool Utils::Fs::isValidFileSystemName(const QString &name, bool allowSeparators)
return !name.contains(regex);
}
qlonglong Utils::Fs::freeDiskSpaceOnPath(QString path)
qulonglong Utils::Fs::freeDiskSpaceOnPath(const QString &path)
{
if (path.isEmpty()) return -1;
QDir dir_path(path);
if (!dir_path.exists()) {
QStringList parts = path.split("/");
while (parts.size() > 1 && !QDir(parts.join("/")).exists()) {
parts.removeLast();
}
dir_path = QDir(parts.join("/"));
if (!dir_path.exists()) return -1;
}
Q_ASSERT(dir_path.exists());
if (path.isEmpty()) return 0;
#ifndef Q_OS_WIN
unsigned long long available;
#ifdef Q_OS_HAIKU
const QString statfs_path = dir_path.path() + "/.";
dev_t device = dev_for_path (qPrintable(statfs_path));
if (device >= 0) {
fs_info info;
if (fs_stat_dev(device, &info) == B_OK) {
available = ((unsigned long long)(info.free_blocks * info.block_size));
return available;
}
QDir dirPath(path);
if (!dirPath.exists()) {
QStringList parts = path.split("/");
while (parts.size() > 1 && !QDir(parts.join("/")).exists())
parts.removeLast();
dirPath = QDir(parts.join("/"));
if (!dirPath.exists()) return 0;
}
return -1;
Q_ASSERT(dirPath.exists());
#if defined(Q_OS_WIN)
ULARGE_INTEGER bytesFree;
LPCWSTR nativePath = reinterpret_cast<LPCWSTR>((toNativePath(dirPath.path())).utf16());
if (GetDiskFreeSpaceExW(nativePath, &bytesFree, NULL, NULL) == 0)
return 0;
return bytesFree.QuadPart;
#elif defined(Q_OS_HAIKU)
const QString statfsPath = dirPath.path() + "/.";
dev_t device = dev_for_path(qPrintable(statfsPath));
if (device < 0)
return 0;
fs_info info;
if (fs_stat_dev(device, &info) != B_OK)
return 0;
return ((qulonglong) info.free_blocks * (qulonglong) info.block_size);
#else
struct statfs stats;
const QString statfs_path = dir_path.path() + "/.";
const int ret = statfs(qPrintable(statfs_path), &stats);
if (ret == 0) {
available = ((unsigned long long)stats.f_bavail)
* ((unsigned long long)stats.f_bsize);
return available;
}
else {
return -1;
}
#endif
#else
typedef BOOL (WINAPI *GetDiskFreeSpaceEx_t)(LPCTSTR,
PULARGE_INTEGER,
PULARGE_INTEGER,
PULARGE_INTEGER);
GetDiskFreeSpaceEx_t pGetDiskFreeSpaceEx =
(GetDiskFreeSpaceEx_t)::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "GetDiskFreeSpaceExW");
if (pGetDiskFreeSpaceEx) {
ULARGE_INTEGER bytesFree, bytesTotal;
unsigned long long *ret;
if (pGetDiskFreeSpaceEx((LPCTSTR)(toNativePath(dir_path.path())).utf16(), &bytesFree, &bytesTotal, NULL)) {
ret = (unsigned long long*)&bytesFree;
return *ret;
}
else {
return -1;
}
}
else {
return -1;
}
const QString statfsPath = dirPath.path() + "/.";
const int ret = statfs(qPrintable(statfsPath), &stats);
if (ret != 0)
return 0;
return ((qulonglong) stats.f_bavail * (qulonglong) stats.f_bsize);
#endif
}
@@ -378,19 +354,17 @@ QString Utils::Fs::expandPathAbs(const QString& path)
QString Utils::Fs::QDesktopServicesDataLocation()
{
QString result;
#ifdef Q_OS_WIN
LPWSTR path=new WCHAR[256];
if (SHGetSpecialFolderPath(0, path, CSIDL_LOCAL_APPDATA, FALSE))
#if defined(Q_OS_WIN)
wchar_t path[MAX_PATH + 1] = {L'\0'};
if (SHGetSpecialFolderPathW(0, path, CSIDL_LOCAL_APPDATA, FALSE))
result = fromNativePath(QString::fromWCharArray(path));
if (!QCoreApplication::applicationName().isEmpty())
result += QLatin1String("/") + qApp->applicationName();
#else
#ifdef Q_OS_MAC
#elif defined(Q_OS_MAC)
FSRef ref;
OSErr err = FSFindFolder(kUserDomain, kApplicationSupportFolderType, false, &ref);
if (err)
return QString();
QString path;
QByteArray ba(2048, 0);
if (FSRefMakePath(&ref, reinterpret_cast<UInt8 *>(ba.data()), ba.size()) == noErr)
result = QString::fromUtf8(ba).normalized(QString::NormalizationForm_C);
@@ -402,7 +376,6 @@ QString Utils::Fs::QDesktopServicesDataLocation()
xdgDataHome += QLatin1String("/data/")
+ qApp->applicationName();
result = xdgDataHome;
#endif
#endif
if (!result.endsWith("/"))
result += "/";
@@ -518,3 +491,10 @@ QString Utils::Fs::cacheLocation()
locationDir.mkpath(locationDir.absolutePath());
return location;
}
QString Utils::Fs::tempPath()
{
static const QString path = QDir::tempPath() + "/.qBittorrent/";
QDir().mkdir(path);
return path;
}

View File

@@ -50,7 +50,7 @@ namespace Utils
bool sameFiles(const QString& path1, const QString& path2);
QString toValidFileSystemName(const QString &name, bool allowSeparators = false);
bool isValidFileSystemName(const QString& name, bool allowSeparators = false);
qlonglong freeDiskSpaceOnPath(QString path);
qulonglong freeDiskSpaceOnPath(const QString &path);
QString branchPath(const QString& file_path, QString* removed = 0);
bool sameFileNames(const QString& first, const QString& second);
QString expandPath(const QString& path);
@@ -67,6 +67,7 @@ namespace Utils
/* End of Qt4 code */
QString cacheLocation();
QString tempPath();
}
}

View File

@@ -94,7 +94,73 @@ static struct { const char *source; const char *comment; } units[] = {
void Utils::Misc::shutdownComputer(const ShutdownDialogAction &action)
{
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) && defined(QT_DBUS_LIB)
#if defined(Q_OS_WIN)
HANDLE hToken; // handle to process token
TOKEN_PRIVILEGES tkp; // pointer to token structure
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return;
// Get the LUID for shutdown privilege.
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
&tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Get shutdown privilege for this process.
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
(PTOKEN_PRIVILEGES) NULL, 0);
// Cannot test the return value of AdjustTokenPrivileges.
if (GetLastError() != ERROR_SUCCESS)
return;
if (action == ShutdownDialogAction::Suspend)
SetSuspendState(false, false, false);
else if (action == ShutdownDialogAction::Hibernate)
SetSuspendState(true, false, false);
else
InitiateSystemShutdownA(0, QCoreApplication::translate("misc", "qBittorrent will shutdown the computer now because all downloads are complete.").toLocal8Bit().data(), 10, true, false);
// Disable shutdown privilege.
tkp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
#elif defined(Q_OS_MAC)
AEEventID EventToSend;
if (action != ShutdownDialogAction::Shutdown)
EventToSend = kAESleep;
else
EventToSend = kAEShutDown;
AEAddressDesc targetDesc;
static const ProcessSerialNumber kPSNOfSystemProcess = { 0, kSystemProcess };
AppleEvent eventReply = {typeNull, NULL};
AppleEvent appleEventToSend = {typeNull, NULL};
OSStatus error = AECreateDesc(typeProcessSerialNumber, &kPSNOfSystemProcess,
sizeof(kPSNOfSystemProcess), &targetDesc);
if (error != noErr)
return;
error = AECreateAppleEvent(kCoreEventClass, EventToSend, &targetDesc,
kAutoGenerateReturnID, kAnyTransactionID, &appleEventToSend);
AEDisposeDesc(&targetDesc);
if (error != noErr)
return;
error = AESend(&appleEventToSend, &eventReply, kAENoReply,
kAENormalPriority, kAEDefaultTimeout, NULL, NULL);
AEDisposeDesc(&appleEventToSend);
if (error != noErr)
return;
AEDisposeDesc(&eventReply);
#elif (defined(Q_OS_UNIX) && defined(QT_DBUS_LIB))
// Use dbus to power off / suspend the system
if (action != ShutdownDialogAction::Shutdown) {
// Some recent systems use systemd's logind
@@ -147,73 +213,9 @@ void Utils::Misc::shutdownComputer(const ShutdownDialogAction &action)
QDBusConnection::systemBus());
halIface.call("Shutdown");
}
#endif
#ifdef Q_OS_MAC
AEEventID EventToSend;
if (action != ShutdownDialogAction::Shutdown)
EventToSend = kAESleep;
else
EventToSend = kAEShutDown;
AEAddressDesc targetDesc;
static const ProcessSerialNumber kPSNOfSystemProcess = { 0, kSystemProcess };
AppleEvent eventReply = {typeNull, NULL};
AppleEvent appleEventToSend = {typeNull, NULL};
OSStatus error = AECreateDesc(typeProcessSerialNumber, &kPSNOfSystemProcess,
sizeof(kPSNOfSystemProcess), &targetDesc);
if (error != noErr)
return;
error = AECreateAppleEvent(kCoreEventClass, EventToSend, &targetDesc,
kAutoGenerateReturnID, kAnyTransactionID, &appleEventToSend);
AEDisposeDesc(&targetDesc);
if (error != noErr)
return;
error = AESend(&appleEventToSend, &eventReply, kAENoReply,
kAENormalPriority, kAEDefaultTimeout, NULL, NULL);
AEDisposeDesc(&appleEventToSend);
if (error != noErr)
return;
AEDisposeDesc(&eventReply);
#endif
#ifdef Q_OS_WIN
HANDLE hToken; // handle to process token
TOKEN_PRIVILEGES tkp; // pointer to token structure
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return;
// Get the LUID for shutdown privilege.
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
&tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Get shutdown privilege for this process.
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
(PTOKEN_PRIVILEGES) NULL, 0);
// Cannot test the return value of AdjustTokenPrivileges.
if (GetLastError() != ERROR_SUCCESS)
return;
if (action == ShutdownDialogAction::Suspend)
SetSuspendState(false, false, false);
else if (action == ShutdownDialogAction::Hibernate)
SetSuspendState(true, false, false);
else
InitiateSystemShutdownA(0, QCoreApplication::translate("misc", "qBittorrent will shutdown the computer now because all downloads are complete.").toLocal8Bit().data(), 10, true, false);
// Disable shutdown privilege.
tkp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
(PTOKEN_PRIVILEGES) NULL, 0);
#else
Q_UNUSED(action);
#endif
}
@@ -356,14 +358,22 @@ QString Utils::Misc::friendlyUnit(qint64 bytesValue, bool isSpeed)
return QCoreApplication::translate("misc", "Unknown", "Unknown (size)");
QString ret;
if (unit == SizeUnit::Byte)
ret = QString::number(bytesValue) + " " + unitString(unit);
ret = QString::number(bytesValue) + QString::fromUtf8(C_NON_BREAKING_SPACE) + unitString(unit);
else
ret = Utils::String::fromDouble(friendlyVal, 1) + " " + unitString(unit);
ret = Utils::String::fromDouble(friendlyVal, friendlyUnitPrecision(unit)) + QString::fromUtf8(C_NON_BREAKING_SPACE) + unitString(unit);
if (isSpeed)
ret += QCoreApplication::translate("misc", "/s", "per second");
return ret;
}
int Utils::Misc::friendlyUnitPrecision(SizeUnit unit)
{
// friendlyUnit's number of digits after the decimal point
if (unit <= SizeUnit::MebiByte) return 1;
else if (unit == SizeUnit::GibiByte) return 2;
else return 3;
}
qlonglong Utils::Misc::sizeInBytes(qreal size, Utils::Misc::SizeUnit unit)
{
for (int i = 0; i < static_cast<int>(unit); ++i)
@@ -430,21 +440,27 @@ QString Utils::Misc::userFriendlyDuration(qlonglong seconds)
{
if ((seconds < 0) || (seconds >= MAX_ETA))
return QString::fromUtf8(C_INFINITY);
if (seconds == 0)
return "0";
if (seconds < 60)
return QCoreApplication::translate("misc", "< 1m", "< 1 minute");
int minutes = seconds / 60;
qlonglong minutes = seconds / 60;
if (minutes < 60)
return QCoreApplication::translate("misc", "%1m", "e.g: 10minutes").arg(QString::number(minutes));
int hours = minutes / 60;
minutes = minutes - hours * 60;
qlonglong hours = minutes / 60;
minutes -= hours * 60;
if (hours < 24)
return QCoreApplication::translate("misc", "%1h %2m", "e.g: 3hours 5minutes").arg(QString::number(hours)).arg(QString::number(minutes));
int days = hours / 24;
hours = hours - days * 24;
qlonglong days = hours / 24;
hours -= days * 24;
if (days < 100)
return QCoreApplication::translate("misc", "%1d %2h", "e.g: 2days 10hours").arg(QString::number(days)).arg(QString::number(hours));
return QString::fromUtf8(C_INFINITY);
}
@@ -580,7 +596,7 @@ void Utils::Misc::openFolderSelect(const QString &absolutePath)
}
#ifdef Q_OS_WIN
HRESULT hresult = ::CoInitializeEx(nullptr, COINIT_MULTITHREADED);
ITEMIDLIST *pidl = ::ILCreateFromPathW(reinterpret_cast<PCTSTR>(Utils::Fs::toNativePath(path).utf16()));
PIDLIST_ABSOLUTE pidl = ::ILCreateFromPathW(reinterpret_cast<PCTSTR>(Utils::Fs::toNativePath(path).utf16()));
if (pidl) {
::SHOpenFolderAndSelectItems(pidl, 0, nullptr, 0);
::ILFree(pidl);

View File

@@ -88,6 +88,7 @@ namespace Utils
// value must be given in bytes
bool friendlyUnit(qint64 sizeInBytes, qreal& val, SizeUnit& unit);
QString friendlyUnit(qint64 bytesValue, bool isSpeed = false);
int friendlyUnitPrecision(SizeUnit unit);
qint64 sizeInBytes(qreal size, SizeUnit unit);
bool isPreviewable(const QString& extension);

View File

@@ -177,8 +177,12 @@ QString Utils::String::fromStdString(const std::string &str)
std::string Utils::String::toStdString(const QString &str)
{
#ifdef QBT_USES_QT5
return str.toStdString();
#else
QByteArray utf8 = str.toUtf8();
return std::string(utf8.constData(), utf8.length());
#endif
}
// to send numbers instead of strings with suffixes
@@ -207,3 +211,12 @@ bool Utils::String::slowEquals(const QByteArray &a, const QByteArray &b)
return (diff == 0);
}
QString Utils::String::toHtmlEscaped(const QString &str)
{
#ifdef QBT_USES_QT5
return str.toHtmlEscaped();
#else
return Qt::escape(str);
#endif
}

View File

@@ -47,6 +47,8 @@ namespace Utils
// Taken from https://crackstation.net/hashing-security.htm
bool slowEquals(const QByteArray &a, const QByteArray &b);
QString toHtmlEscaped(const QString &str);
bool naturalCompareCaseSensitive(const QString &left, const QString &right);
bool naturalCompareCaseInsensitive(const QString &left, const QString &right);
}

View File

@@ -32,6 +32,8 @@ addnewtorrentdialog.h
advancedsettings.h
advancedsettings.h
autoexpandabledialog.h
categoryfiltermodel.h
categoryfilterwidget.h
cookiesdialog.h
cookiesmodel.h
deletionconfirmationdlg.h
@@ -71,6 +73,8 @@ set(QBT_GUI_SOURCES
addnewtorrentdialog.cpp
advancedsettings.cpp
autoexpandabledialog.cpp
categoryfiltermodel.cpp
categoryfilterwidget.cpp
cookiesdialog.cpp
cookiesmodel.cpp
executionlog.cpp

View File

@@ -61,7 +61,7 @@ public:
"</table>"
"</p>")
.arg(tr("An advanced BitTorrent client programmed in C++, based on Qt toolkit and libtorrent-rasterbar."))
.arg(tr("Copyright %1 2006-2016 The qBittorrent project").arg(QString::fromUtf8(C_COPYRIGHT)))
.arg(tr("Copyright %1 2006-2017 The qBittorrent project").arg(QString::fromUtf8(C_COPYRIGHT)))
.arg(tr("Home Page:"))
.arg(tr("Forum:"))
.arg(tr("Bug Tracker:"));

View File

@@ -58,7 +58,6 @@
#define SETTINGS_KEY(name) "AddNewTorrentDialog/" name
const QString KEY_ENABLED = SETTINGS_KEY("Enabled");
const QString KEY_DEFAULTSAVEPATH = SETTINGS_KEY("DefaultSavePath");
const QString KEY_DEFAULTCATEGORY = SETTINGS_KEY("DefaultCategory");
const QString KEY_TREEHEADERSTATE = SETTINGS_KEY("TreeHeaderState");
const QString KEY_WIDTH = SETTINGS_KEY("Width");
@@ -118,7 +117,7 @@ AddNewTorrentDialog::AddNewTorrentDialog(QWidget *parent)
// Signal / slots
connect(ui->adv_button, SIGNAL(clicked(bool)), SLOT(showAdvancedSettings(bool)));
connect(ui->doNotDeleteTorrentCheckBox, SIGNAL(clicked(bool)), SLOT(doNotDeleteTorrentClicked(bool)));
editHotkey = new QShortcut(QKeySequence("F2"), ui->contentTreeView, 0, 0, Qt::WidgetShortcut);
editHotkey = new QShortcut(Qt::Key_F2, ui->contentTreeView, 0, 0, Qt::WidgetShortcut);
connect(editHotkey, SIGNAL(activated()), SLOT(renameSelectedFile()));
connect(ui->contentTreeView, SIGNAL(doubleClicked(QModelIndex)), SLOT(renameSelectedFile()));
@@ -394,7 +393,7 @@ void AddNewTorrentDialog::onSavePathChanged(int index)
ui->defaultSavePathCheckBox->setChecked(false);
ui->defaultSavePathCheckBox->setVisible(
QDir(ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString())
!= QDir(defaultSavePath()));
!= QDir(BitTorrent::Session::instance()->defaultSavePath()));
// Remember index
m_oldIndex = index;
@@ -567,7 +566,7 @@ void AddNewTorrentDialog::setdialogPosition()
void AddNewTorrentDialog::populateSavePathComboBox()
{
QString defSavePath = defaultSavePath();
QString defSavePath = BitTorrent::Session::instance()->defaultSavePath();
ui->savePathComboBox->clear();
ui->savePathComboBox->addItem(Utils::Fs::toNativePath(defSavePath), defSavePath);
@@ -646,7 +645,7 @@ void AddNewTorrentDialog::accept()
params.savePath = savePath;
saveSavePathHistory();
if (ui->defaultSavePathCheckBox->isChecked())
settings()->storeValue(KEY_DEFAULTSAVEPATH, savePath);
BitTorrent::Session::instance()->setDefaultSavePath(savePath);
}
setEnabled(!ui->never_show_cb->isChecked());
@@ -690,7 +689,6 @@ void AddNewTorrentDialog::updateMetadata(const BitTorrent::TorrentInfo &info)
// Update UI
setupTreeview();
TMMChanged(ui->comboTTM->currentIndex());
setMetadataProgressIndicator(false, tr("Metadata retrieval complete"));
}
@@ -744,13 +742,6 @@ void AddNewTorrentDialog::setupTreeview()
setdialogPosition();
}
QString AddNewTorrentDialog::defaultSavePath() const
{
return Utils::Fs::fromNativePath(
settings()->loadValue(KEY_DEFAULTSAVEPATH,
BitTorrent::Session::instance()->defaultSavePath()).toString());
}
void AddNewTorrentDialog::handleDownloadFailed(const QString &url, const QString &reason)
{
MessageBoxRaised::critical(0, tr("Download Error"), QString("Cannot download '%1': %2").arg(url).arg(reason));

View File

@@ -97,7 +97,6 @@ private:
void saveState();
void setMetadataProgressIndicator(bool visibleIndicator, const QString &labelText = QString());
void setupTreeview();
QString defaultSavePath() const;
void setCommentText(const QString &str) const;
void showEvent(QShowEvent *event) override;

View File

@@ -27,11 +27,14 @@
*/
#include "advancedsettings.h"
#include <QFont>
#include <QHeaderView>
#include <QHostAddress>
#include <QNetworkInterface>
#include "app/application.h"
#include "base/bittorrent/session.h"
#include "base/preferences.h"
#include "gui/mainwindow.h"
@@ -63,6 +66,7 @@ enum AdvSettingsRows
RESOLVE_COUNTRIES,
PROGRAM_NOTIFICATIONS,
TORRENT_ADDED_NOTIFICATIONS,
DOWNLOAD_TRACKER_FAVICON,
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
USE_ICON_THEME,
#endif
@@ -83,9 +87,8 @@ enum AdvSettingsRows
// seeding
SUPER_SEEDING,
// tracker
TRACKER_EXCHANGE,
ANNOUNCE_ALL_TRACKERS,
NETWORK_ADDRESS,
ANNOUNCE_IP,
ROW_COUNT
};
@@ -116,61 +119,63 @@ AdvancedSettings::AdvancedSettings(QWidget *parent)
void AdvancedSettings::saveAdvancedSettings()
{
Preferences* const pref = Preferences::instance();
BitTorrent::Session *const session = BitTorrent::Session::instance();
// Disk write cache
pref->setDiskCacheSize(spin_cache.value());
pref->setDiskCacheTTL(spin_cache_ttl.value());
session->setDiskCacheSize(spin_cache.value());
session->setDiskCacheTTL(spin_cache_ttl.value());
// Enable OS cache
pref->setOsCache(cb_os_cache.isChecked());
session->setUseOSCache(cb_os_cache.isChecked());
// Save resume data interval
pref->setSaveResumeDataInterval(spin_save_resume_data_interval.value());
session->setSaveResumeDataInterval(spin_save_resume_data_interval.value());
// Outgoing ports
pref->setOutgoingPortsMin(outgoing_ports_min.value());
pref->setOutgoingPortsMax(outgoing_ports_max.value());
session->setOutgoingPortsMin(outgoing_ports_min.value());
session->setOutgoingPortsMax(outgoing_ports_max.value());
// Recheck torrents on completion
pref->recheckTorrentsOnCompletion(cb_recheck_completed.isChecked());
// Transfer list refresh interval
pref->setRefreshInterval(spin_list_refresh.value());
session->setRefreshInterval(spin_list_refresh.value());
// Peer resolution
pref->resolvePeerCountries(cb_resolve_countries.isChecked());
pref->resolvePeerHostNames(cb_resolve_hosts.isChecked());
// Max Half-Open connections
pref->setMaxHalfOpenConnections(spin_maxhalfopen.value());
session->setMaxHalfOpenConnections(spin_maxhalfopen.value());
// Super seeding
pref->enableSuperSeeding(cb_super_seeding.isChecked());
session->setSuperSeedingEnabled(cb_super_seeding.isChecked());
// Network interface
if (combo_iface.currentIndex() == 0) {
// All interfaces (default)
pref->setNetworkInterface(QString::null);
pref->setNetworkInterfaceName(QString::null);
session->setNetworkInterface(QString());
session->setNetworkInterfaceName(QString());
}
else {
pref->setNetworkInterface(combo_iface.itemData(combo_iface.currentIndex()).toString());
pref->setNetworkInterfaceName(combo_iface.currentText());
session->setNetworkInterface(combo_iface.itemData(combo_iface.currentIndex()).toString());
session->setNetworkInterfaceName(combo_iface.currentText());
}
// Listen on IPv6 address
pref->setListenIPv6(cb_listen_ipv6.isChecked());
// Interface address
if (combo_iface_address.currentIndex() == 0) {
// All addresses (default)
pref->setNetworkInterfaceAddress(QString::null);
session->setNetworkInterfaceAddress(QString::null);
}
else {
QHostAddress ifaceAddr(combo_iface_address.currentText().trimmed());
ifaceAddr.isNull() ? pref->setNetworkInterfaceAddress(QString::null) : pref->setNetworkInterfaceAddress(ifaceAddr.toString());
ifaceAddr.isNull() ? session->setNetworkInterfaceAddress(QString::null) : session->setNetworkInterfaceAddress(ifaceAddr.toString());
}
// Network Announce address
QHostAddress networkAddr(txt_network_address.text().trimmed());
if (networkAddr.isNull())
pref->setNetworkAddress("");
else
pref->setNetworkAddress(networkAddr.toString());
session->setIPv6Enabled(cb_listen_ipv6.isChecked());
// Announce IP
QHostAddress addr(txtAnnounceIP.text().trimmed());
session->setAnnounceIP(addr.isNull() ? "" : addr.toString());
// Program notification
MainWindow * const mainWindow = static_cast<Application*>(QCoreApplication::instance())->mainWindow();
mainWindow->setNotificationsEnabled(cb_program_notifications.isChecked());
mainWindow->setTorrentAddedNotificationsEnabled(cb_torrent_added_notifications.isChecked());
// Misc GUI properties
mainWindow->setDownloadTrackerFavicon(cb_tracker_favicon.isChecked());
// Tracker
pref->setTrackerEnabled(cb_tracker_status.isChecked());
session->setTrackerEnabled(cb_tracker_status.isChecked());
pref->setTrackerPort(spin_tracker_port.value());
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
pref->setUpdateCheckEnabled(cb_update_check.isChecked());
@@ -180,9 +185,7 @@ void AdvancedSettings::saveAdvancedSettings()
pref->useSystemIconTheme(cb_use_icon_theme.isChecked());
#endif
pref->setConfirmTorrentRecheck(cb_confirm_torrent_recheck.isChecked());
// Tracker exchange
pref->setTrackerExchangeEnabled(cb_enable_tracker_ext.isChecked());
pref->setAnnounceToAllTrackers(cb_announce_all_trackers.isChecked());
session->setAnnounceToAllTrackers(cb_announce_all_trackers.isChecked());
}
void AdvancedSettings::updateCacheSpinSuffix(int value)
@@ -197,7 +200,7 @@ void AdvancedSettings::updateInterfaceAddressCombo()
{
// Try to get the currently selected interface name
const QString ifaceName = combo_iface.itemData(combo_iface.currentIndex()).toString(); // Empty string for the first element
const QString currentAddress = Preferences::instance()->getNetworkInterfaceAddress();
const QString currentAddress = BitTorrent::Session::instance()->networkInterfaceAddress();
//Clear all items and reinsert them, default to all
combo_iface_address.clear();
@@ -233,6 +236,8 @@ void AdvancedSettings::updateInterfaceAddressCombo()
void AdvancedSettings::loadAdvancedSettings()
{
const Preferences* const pref = Preferences::instance();
const BitTorrent::Session *const session = BitTorrent::Session::instance();
// add section headers
QFont boldFont;
boldFont.setBold(true);
@@ -255,33 +260,33 @@ void AdvancedSettings::loadAdvancedSettings()
// allocate 1536MiB and leave 512MiB to the rest of program data in RAM
spin_cache.setMaximum(1536);
#endif
spin_cache.setValue(pref->diskCacheSize());
spin_cache.setValue(session->diskCacheSize());
updateCacheSpinSuffix(spin_cache.value());
addRow(DISK_CACHE, tr("Disk write cache size"), &spin_cache);
// Disk cache expiry
spin_cache_ttl.setMinimum(15);
spin_cache_ttl.setMaximum(600);
spin_cache_ttl.setValue(pref->diskCacheTTL());
spin_cache_ttl.setValue(session->diskCacheTTL());
spin_cache_ttl.setSuffix(tr(" s", " seconds"));
addRow(DISK_CACHE_TTL, tr("Disk cache expiry interval"), &spin_cache_ttl);
// Enable OS cache
cb_os_cache.setChecked(pref->osCache());
cb_os_cache.setChecked(session->useOSCache());
addRow(OS_CACHE, tr("Enable OS cache"), &cb_os_cache);
// Save resume data interval
spin_save_resume_data_interval.setMinimum(1);
spin_save_resume_data_interval.setMaximum(1440);
spin_save_resume_data_interval.setValue(pref->saveResumeDataInterval());
spin_save_resume_data_interval.setValue(session->saveResumeDataInterval());
spin_save_resume_data_interval.setSuffix(tr(" m", " minutes"));
addRow(SAVE_RESUME_DATA_INTERVAL, tr("Save resume data interval", "How often the fastresume file is saved."), &spin_save_resume_data_interval);
// Outgoing port Min
outgoing_ports_min.setMinimum(0);
outgoing_ports_min.setMaximum(65535);
outgoing_ports_min.setValue(pref->outgoingPortsMin());
outgoing_ports_min.setValue(session->outgoingPortsMin());
addRow(OUTGOING_PORT_MIN, tr("Outgoing ports (Min) [0: Disabled]"), &outgoing_ports_min);
// Outgoing port Min
outgoing_ports_max.setMinimum(0);
outgoing_ports_max.setMaximum(65535);
outgoing_ports_max.setValue(pref->outgoingPortsMax());
outgoing_ports_max.setValue(session->outgoingPortsMax());
addRow(OUTGOING_PORT_MAX, tr("Outgoing ports (Max) [0: Disabled]"), &outgoing_ports_max);
// Recheck completed torrents
cb_recheck_completed.setChecked(pref->recheckTorrentsOnCompletion());
@@ -289,7 +294,7 @@ void AdvancedSettings::loadAdvancedSettings()
// Transfer list refresh interval
spin_list_refresh.setMinimum(30);
spin_list_refresh.setMaximum(99999);
spin_list_refresh.setValue(pref->getRefreshInterval());
spin_list_refresh.setValue(session->refreshInterval());
spin_list_refresh.setSuffix(tr(" ms", " milliseconds"));
addRow(LIST_REFRESH, tr("Transfer list refresh interval"), &spin_list_refresh);
// Resolve Peer countries
@@ -301,14 +306,14 @@ void AdvancedSettings::loadAdvancedSettings()
// Max Half Open connections
spin_maxhalfopen.setMinimum(0);
spin_maxhalfopen.setMaximum(99999);
spin_maxhalfopen.setValue(pref->getMaxHalfOpenConnections());
spin_maxhalfopen.setValue(session->maxHalfOpenConnections());
addRow(MAX_HALF_OPEN, tr("Maximum number of half-open connections [0: Unlimited]"), &spin_maxhalfopen);
// Super seeding
cb_super_seeding.setChecked(pref->isSuperSeedingEnabled());
cb_super_seeding.setChecked(session->isSuperSeedingEnabled());
addRow(SUPER_SEEDING, tr("Strict super seeding"), &cb_super_seeding);
// Network interface
combo_iface.addItem(tr("Any interface", "i.e. Any network interface"));
const QString current_iface = pref->getNetworkInterface();
const QString current_iface = session->networkInterface();
bool interface_exists = current_iface.isEmpty();
int i = 1;
foreach (const QNetworkInterface& iface, QNetworkInterface::allInterfaces()) {
@@ -328,7 +333,7 @@ void AdvancedSettings::loadAdvancedSettings()
}
// Saved interface does not exist, show it anyway
if (!interface_exists) {
combo_iface.addItem(pref->getNetworkInterfaceName(), current_iface);
combo_iface.addItem(session->networkInterfaceName(), current_iface);
combo_iface.setCurrentIndex(i);
}
addRow(NETWORK_IFACE, tr("Network Interface (requires restart)"), &combo_iface);
@@ -336,11 +341,11 @@ void AdvancedSettings::loadAdvancedSettings()
updateInterfaceAddressCombo();
addRow(NETWORK_IFACE_ADDRESS, tr("Optional IP Address to bind to (requires restart)"), &combo_iface_address);
// Listen on IPv6 address
cb_listen_ipv6.setChecked(pref->getListenIPv6());
cb_listen_ipv6.setChecked(session->isIPv6Enabled());
addRow(NETWORK_LISTEN_IPV6, tr("Listen on IPv6 address (requires restart)"), &cb_listen_ipv6);
// Announce address
txt_network_address.setText(pref->getNetworkAddress());
addRow(NETWORK_ADDRESS, tr("IP Address to report to trackers (requires restart)"), &txt_network_address);
// Announce IP
txtAnnounceIP.setText(session->announceIP());
addRow(ANNOUNCE_IP, tr("IP Address to report to trackers (requires restart)"), &txtAnnounceIP);
// Program notifications
const MainWindow * const mainWindow = static_cast<Application*>(QCoreApplication::instance())->mainWindow();
@@ -349,8 +354,12 @@ void AdvancedSettings::loadAdvancedSettings()
// Torrent added notifications
cb_torrent_added_notifications.setChecked(mainWindow->isTorrentAddedNotificationsEnabled());
addRow(TORRENT_ADDED_NOTIFICATIONS, tr("Display notifications for added torrents"), &cb_torrent_added_notifications);
// Download tracker's favicon
cb_tracker_favicon.setChecked(mainWindow->isDownloadTrackerFavicon());
addRow(DOWNLOAD_TRACKER_FAVICON, tr("Download tracker's favicon"), &cb_tracker_favicon);
// Tracker State
cb_tracker_status.setChecked(pref->isTrackerEnabled());
cb_tracker_status.setChecked(session->isTrackerEnabled());
addRow(TRACKER_STATUS, tr("Enable embedded tracker"), &cb_tracker_status);
// Tracker port
spin_tracker_port.setMinimum(1);
@@ -368,17 +377,18 @@ void AdvancedSettings::loadAdvancedSettings()
// Torrent recheck confirmation
cb_confirm_torrent_recheck.setChecked(pref->confirmTorrentRecheck());
addRow(CONFIRM_RECHECK_TORRENT, tr("Confirm torrent recheck"), &cb_confirm_torrent_recheck);
// Tracker exchange
cb_enable_tracker_ext.setChecked(pref->trackerExchangeEnabled());
addRow(TRACKER_EXCHANGE, tr("Exchange trackers with other peers"), &cb_enable_tracker_ext);
// Announce to all trackers
cb_announce_all_trackers.setChecked(pref->announceToAllTrackers());
cb_announce_all_trackers.setChecked(session->announceToAllTrackers());
addRow(ANNOUNCE_ALL_TRACKERS, tr("Always announce to all trackers"), &cb_announce_all_trackers);
}
template <typename T>
void AdvancedSettings::addRow(int row, const QString &rowText, T* widget)
{
// ignore mouse wheel event
static WheelEventEater filter;
widget->installEventFilter(&filter);
setItem(row, PROPERTY, new QTableWidgetItem(rowText));
setCellWidget(row, VALUE, widget);

View File

@@ -29,6 +29,7 @@
#ifndef ADVANCEDSETTINGS_H
#define ADVANCEDSETTINGS_H
#include <QEvent>
#include <QLabel>
#include <QSpinBox>
#include <QCheckBox>
@@ -37,6 +38,22 @@
#include <QTableWidget>
class WheelEventEater: public QObject
{
Q_OBJECT
private:
bool eventFilter(QObject *obj, QEvent *event)
{
switch (event->type()) {
case QEvent::Wheel:
return true;
default:
return QObject::eventFilter(obj, event);
}
}
};
class AdvancedSettings: public QTableWidget
{
Q_OBJECT
@@ -60,11 +77,11 @@ private:
QLabel labelQbtLink, labelLibtorrentLink;
QSpinBox spin_cache, spin_save_resume_data_interval, outgoing_ports_min, outgoing_ports_max, spin_list_refresh, spin_maxhalfopen, spin_tracker_port, spin_cache_ttl;
QCheckBox cb_os_cache, cb_recheck_completed, cb_resolve_countries, cb_resolve_hosts,
cb_super_seeding, cb_program_notifications, cb_torrent_added_notifications, cb_tracker_status,
cb_confirm_torrent_recheck, cb_enable_tracker_ext, cb_listen_ipv6, cb_announce_all_trackers;
QCheckBox cb_os_cache, cb_recheck_completed, cb_resolve_countries, cb_resolve_hosts, cb_super_seeding,
cb_program_notifications, cb_torrent_added_notifications, cb_tracker_favicon, cb_tracker_status,
cb_confirm_torrent_recheck, cb_listen_ipv6, cb_announce_all_trackers;
QComboBox combo_iface, combo_iface_address;
QLineEdit txt_network_address;
QLineEdit txtAnnounceIP;
// OS dependent settings
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)

View File

@@ -18,15 +18,6 @@
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QSlider" name="bandwidthSlider">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="sliderPosition">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>

View File

@@ -0,0 +1,442 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#include "categoryfiltermodel.h"
#include <QHash>
#include <QIcon>
#include "base/bittorrent/torrenthandle.h"
#include "base/bittorrent/session.h"
#include "guiiconprovider.h"
class CategoryModelItem
{
public:
CategoryModelItem()
: m_parent(nullptr)
, m_torrentsCount(0)
{
}
CategoryModelItem(CategoryModelItem *parent, QString categoryName, int torrentsCount = 0)
: m_parent(nullptr)
, m_name(categoryName)
, m_torrentsCount(torrentsCount)
{
if (parent)
parent->addChild(m_name, this);
}
~CategoryModelItem()
{
clear();
if (m_parent) {
m_parent->m_torrentsCount -= m_torrentsCount;
const QString uid = m_parent->m_children.key(this);
m_parent->m_children.remove(uid);
m_parent->m_childUids.removeOne(uid);
}
}
QString name() const
{
return m_name;
}
QString fullName() const
{
if (!m_parent || m_parent->name().isEmpty())
return m_name;
return QString("%1/%2").arg(m_parent->fullName()).arg(m_name);
}
CategoryModelItem *parent() const
{
return m_parent;
}
int torrentsCount() const
{
return m_torrentsCount;
}
void increaseTorrentsCount()
{
++m_torrentsCount;
if (m_parent)
m_parent->increaseTorrentsCount();
}
void decreaseTorrentsCount()
{
--m_torrentsCount;
if (m_parent)
m_parent->decreaseTorrentsCount();
}
int pos() const
{
if (!m_parent) return -1;
return m_parent->m_childUids.indexOf(m_name);
}
bool hasChild(const QString &name) const
{
return m_children.contains(name);
}
int childCount() const
{
return m_children.count();
}
CategoryModelItem *child(const QString &uid) const
{
return m_children.value(uid);
}
CategoryModelItem *childAt(int index) const
{
if ((index < 0) || (index >= m_childUids.count()))
return nullptr;
return m_children[m_childUids[index]];
}
void addChild(const QString &uid, CategoryModelItem *item)
{
Q_ASSERT(item);
Q_ASSERT(!item->parent());
Q_ASSERT(!m_children.contains(uid));
item->m_parent = this;
m_children[uid] = item;
auto pos = std::lower_bound(m_childUids.begin(), m_childUids.end(), uid);
m_childUids.insert(pos, uid);
m_torrentsCount += item->torrentsCount();
}
void clear()
{
// use copy of m_children for qDeleteAll
// to avoid collision when child removes
// itself from parent children
qDeleteAll(decltype(m_children)(m_children));
}
private:
CategoryModelItem *m_parent;
QString m_name;
int m_torrentsCount;
QHash<QString, CategoryModelItem *> m_children;
QStringList m_childUids;
};
namespace
{
QString shortName(const QString &fullName)
{
int pos = fullName.lastIndexOf(QLatin1Char('/'));
if (pos >= 0)
return fullName.mid(pos + 1);
return fullName;
}
}
CategoryFilterModel::CategoryFilterModel(QObject *parent)
: QAbstractItemModel(parent)
, m_rootItem(new CategoryModelItem)
{
auto session = BitTorrent::Session::instance();
connect(session, SIGNAL(categoryAdded(QString)), SLOT(categoryAdded(QString)));
connect(session, SIGNAL(categoryRemoved(QString)), SLOT(categoryRemoved(QString)));
connect(session, SIGNAL(torrentCategoryChanged(BitTorrent::TorrentHandle *const, QString))
, SLOT(torrentCategoryChanged(BitTorrent::TorrentHandle *const, QString)));
connect(session, SIGNAL(subcategoriesSupportChanged()), SLOT(subcategoriesSupportChanged()));
connect(session, SIGNAL(torrentAdded(BitTorrent::TorrentHandle *const))
, SLOT(torrentAdded(BitTorrent::TorrentHandle *const)));
connect(session, SIGNAL(torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const))
, SLOT(torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const)));
populate();
}
CategoryFilterModel::~CategoryFilterModel()
{
delete m_rootItem;
}
int CategoryFilterModel::columnCount(const QModelIndex &) const
{
return 1;
}
QVariant CategoryFilterModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) return QVariant();
auto item = static_cast<CategoryModelItem *>(index.internalPointer());
if ((index.column() == 0) && (role == Qt::DecorationRole)) {
return GuiIconProvider::instance()->getIcon("inode-directory");
}
if ((index.column() == 0) && (role == Qt::DisplayRole)) {
return QString(QStringLiteral("%1 (%2)"))
.arg(item->name()).arg(item->torrentsCount());
}
if ((index.column() == 0) && (role == Qt::UserRole)) {
return item->torrentsCount();
}
return QVariant();
}
Qt::ItemFlags CategoryFilterModel::flags(const QModelIndex &index) const
{
if (!index.isValid()) return 0;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
QVariant CategoryFilterModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if ((orientation == Qt::Horizontal) && (role == Qt::DisplayRole))
if (section == 0)
return tr("Categories");
return QVariant();
}
QModelIndex CategoryFilterModel::index(int row, int column, const QModelIndex &parent) const
{
if (column > 0)
return QModelIndex();
if (parent.isValid() && (parent.column() != 0))
return QModelIndex();
auto parentItem = parent.isValid() ? static_cast<CategoryModelItem *>(parent.internalPointer())
: m_rootItem;
if (row < parentItem->childCount())
return createIndex(row, column, parentItem->childAt(row));
return QModelIndex();
}
QModelIndex CategoryFilterModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();
auto item = static_cast<CategoryModelItem *>(index.internalPointer());
if (!item) return QModelIndex();
return this->index(item->parent());
}
int CategoryFilterModel::rowCount(const QModelIndex &parent) const
{
if (parent.column() > 0)
return 0;
if (!parent.isValid())
return m_rootItem->childCount();
auto item = static_cast<CategoryModelItem *>(parent.internalPointer());
if (!item) return 0;
return item->childCount();
}
QModelIndex CategoryFilterModel::index(const QString &categoryName) const
{
return index(findItem(categoryName));
}
QString CategoryFilterModel::categoryName(const QModelIndex &index) const
{
if (!index.isValid()) return QString();
return static_cast<CategoryModelItem *>(index.internalPointer())->fullName();
}
QModelIndex CategoryFilterModel::index(CategoryModelItem *item) const
{
if (!item || !item->parent()) return QModelIndex();
return index(item->pos(), 0, index(item->parent()));
}
void CategoryFilterModel::categoryAdded(const QString &categoryName)
{
CategoryModelItem *parent = m_rootItem;
if (m_isSubcategoriesEnabled) {
QStringList expanded = BitTorrent::Session::expandCategory(categoryName);
if (expanded.count() > 1)
parent = findItem(expanded[expanded.count() - 2]);
}
auto item = new CategoryModelItem(
parent, m_isSubcategoriesEnabled ? shortName(categoryName) : categoryName);
QModelIndex i = index(item);
beginInsertRows(i.parent(), i.row(), i.row());
endInsertRows();
}
void CategoryFilterModel::categoryRemoved(const QString &categoryName)
{
auto item = findItem(categoryName);
if (item) {
QModelIndex i = index(item);
beginRemoveRows(i.parent(), i.row(), i.row());
delete item;
endRemoveRows();
}
}
void CategoryFilterModel::torrentAdded(BitTorrent::TorrentHandle *const torrent)
{
CategoryModelItem *item = findItem(torrent->category());
Q_ASSERT(item);
item->increaseTorrentsCount();
m_rootItem->childAt(0)->increaseTorrentsCount();
}
void CategoryFilterModel::torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent)
{
CategoryModelItem *item = findItem(torrent->category());
Q_ASSERT(item);
item->decreaseTorrentsCount();
m_rootItem->childAt(0)->decreaseTorrentsCount();
}
void CategoryFilterModel::torrentCategoryChanged(BitTorrent::TorrentHandle *const torrent, const QString &oldCategory)
{
QModelIndex i;
auto item = findItem(oldCategory);
Q_ASSERT(item);
item->decreaseTorrentsCount();
i = index(item);
while (i.isValid()) {
emit dataChanged(i, i);
i = parent(i);
}
item = findItem(torrent->category());
Q_ASSERT(item);
item->increaseTorrentsCount();
i = index(item);
while (i.isValid()) {
emit dataChanged(i, i);
i = parent(i);
}
}
void CategoryFilterModel::subcategoriesSupportChanged()
{
beginResetModel();
populate();
endResetModel();
}
void CategoryFilterModel::populate()
{
m_rootItem->clear();
auto session = BitTorrent::Session::instance();
auto torrents = session->torrents();
m_isSubcategoriesEnabled = session->isSubcategoriesEnabled();
const QString UID_ALL;
const QString UID_UNCATEGORIZED(QChar(1));
// All torrents
m_rootItem->addChild(UID_ALL, new CategoryModelItem(nullptr, tr("All"), torrents.count()));
// Uncategorized torrents
using Torrent = BitTorrent::TorrentHandle;
m_rootItem->addChild(
UID_UNCATEGORIZED
, new CategoryModelItem(
nullptr, tr("Uncategorized")
, std::count_if(torrents.begin(), torrents.end()
, [](Torrent *torrent) { return torrent->category().isEmpty(); })));
using Torrent = BitTorrent::TorrentHandle;
foreach (const QString &category, session->categories()) {
if (m_isSubcategoriesEnabled) {
CategoryModelItem *parent = m_rootItem;
foreach (const QString &subcat, session->expandCategory(category)) {
const QString subcatName = shortName(subcat);
if (!parent->hasChild(subcatName)) {
new CategoryModelItem(
parent, subcatName
, std::count_if(torrents.begin(), torrents.end()
, [subcat](Torrent *torrent) { return torrent->category() == subcat; }));
}
parent = parent->child(subcatName);
}
}
else {
new CategoryModelItem(
m_rootItem, category
, std::count_if(torrents.begin(), torrents.end()
, [category](Torrent *torrent) { return torrent->belongsToCategory(category); }));
}
}
}
CategoryModelItem *CategoryFilterModel::findItem(const QString &fullName) const
{
if (fullName.isEmpty())
return m_rootItem->childAt(1); // "Uncategorized" item
if (!m_isSubcategoriesEnabled)
return m_rootItem->child(fullName);
CategoryModelItem *item = m_rootItem;
foreach (const QString &subcat, BitTorrent::Session::expandCategory(fullName)) {
const QString subcatName = shortName(subcat);
if (!item->hasChild(subcatName)) return nullptr;
item = item->child(subcatName);
}
return item;
}

View File

@@ -0,0 +1,79 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#ifndef CATEGORYFILTERMODEL_H
#define CATEGORYFILTERMODEL_H
#include <QAbstractItemModel>
#include <QHash>
#include <QModelIndex>
namespace BitTorrent
{
class TorrentHandle;
}
class CategoryModelItem;
class CategoryFilterModel: public QAbstractItemModel
{
Q_OBJECT
public:
explicit CategoryFilterModel(QObject *parent = nullptr);
~CategoryFilterModel();
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QModelIndex index(const QString &categoryName) const;
QString categoryName(const QModelIndex &index) const;
private slots:
void categoryAdded(const QString &categoryName);
void categoryRemoved(const QString &categoryName);
void torrentAdded(BitTorrent::TorrentHandle *const torrent);
void torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent);
void torrentCategoryChanged(BitTorrent::TorrentHandle *const torrent, const QString &oldCategory);
void subcategoriesSupportChanged();
private:
void populate();
QModelIndex index(CategoryModelItem *item) const;
CategoryModelItem *findItem(const QString &fullName) const;
bool m_isSubcategoriesEnabled;
CategoryModelItem *m_rootItem;
};
#endif // CATEGORYFILTERMODEL_H

View File

@@ -0,0 +1,270 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#include "categoryfilterwidget.h"
#include <QAction>
#include <QHeaderView>
#include <QLayout>
#include <QMenu>
#include <QMessageBox>
#include "base/bittorrent/session.h"
#include "base/utils/misc.h"
#include "autoexpandabledialog.h"
#include "categoryfiltermodel.h"
#include "guiiconprovider.h"
namespace
{
QString getCategoryFilter(const CategoryFilterModel *const model, const QModelIndex &index)
{
QString categoryFilter; // Defaults to All
if (index.isValid()) {
if (!index.parent().isValid() && (index.row() == 1))
categoryFilter = ""; // Uncategorized
else if (index.parent().isValid() || (index.row() > 1))
categoryFilter = model->categoryName(index);
}
return categoryFilter;
}
bool isSpecialItem(const QModelIndex &index)
{
// the first two items at first level are special items:
// 'All' and 'Uncategorized'
return (!index.parent().isValid() && (index.row() <= 1));
}
}
CategoryFilterWidget::CategoryFilterWidget(QWidget *parent)
: QTreeView(parent)
{
setModel(new CategoryFilterModel(this));
setFrameShape(QFrame::NoFrame);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
setUniformRowHeights(true);
setHeaderHidden(true);
setIconSize(Utils::Misc::smallIconSize());
#if defined(Q_OS_MAC)
setAttribute(Qt::WA_MacShowFocusRect, false);
#endif
setContextMenuPolicy(Qt::CustomContextMenu);
setCurrentIndex(model()->index(0, 0));
connect(this, SIGNAL(collapsed(QModelIndex)), SLOT(callUpdateGeometry()));
connect(this, SIGNAL(expanded(QModelIndex)), SLOT(callUpdateGeometry()));
connect(this, SIGNAL(customContextMenuRequested(QPoint)), SLOT(showMenu(QPoint)));
connect(selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex))
, SLOT(onCurrentRowChanged(QModelIndex,QModelIndex)));
connect(model(), SIGNAL(modelReset()), SLOT(callUpdateGeometry()));
}
QString CategoryFilterWidget::currentCategory() const
{
QModelIndex current;
auto selectedRows = selectionModel()->selectedRows();
if (!selectedRows.isEmpty())
current = selectedRows.first();
return getCategoryFilter(static_cast<CategoryFilterModel *>(model()), current);
}
void CategoryFilterWidget::onCurrentRowChanged(const QModelIndex &current, const QModelIndex &previous)
{
Q_UNUSED(previous);
emit categoryChanged(getCategoryFilter(static_cast<CategoryFilterModel *>(model()), current));
}
void CategoryFilterWidget::showMenu(QPoint)
{
QMenu menu(this);
QAction *addAct = menu.addAction(
GuiIconProvider::instance()->getIcon("list-add")
, tr("Add category..."));
connect(addAct, SIGNAL(triggered()), SLOT(addCategory()));
auto selectedRows = selectionModel()->selectedRows();
if (!selectedRows.empty() && !isSpecialItem(selectedRows.first())) {
if (BitTorrent::Session::instance()->isSubcategoriesEnabled()) {
QAction *addSubAct = menu.addAction(
GuiIconProvider::instance()->getIcon("list-add")
, tr("Add subcategory..."));
connect(addSubAct, SIGNAL(triggered()), SLOT(addSubcategory()));
}
QAction *removeAct = menu.addAction(
GuiIconProvider::instance()->getIcon("list-remove")
, tr("Remove category"));
connect(removeAct, SIGNAL(triggered()), SLOT(removeCategory()));
}
QAction *removeUnusedAct = menu.addAction(
GuiIconProvider::instance()->getIcon("list-remove")
, tr("Remove unused categories"));
connect(removeUnusedAct, SIGNAL(triggered()), SLOT(removeUnusedCategories()));
menu.addSeparator();
QAction *startAct = menu.addAction(
GuiIconProvider::instance()->getIcon("media-playback-start")
, tr("Resume torrents"));
connect(startAct, SIGNAL(triggered()), SIGNAL(actionResumeTorrentsTriggered()));
QAction *pauseAct = menu.addAction(
GuiIconProvider::instance()->getIcon("media-playback-pause")
, tr("Pause torrents"));
connect(pauseAct, SIGNAL(triggered()), SIGNAL(actionPauseTorrentsTriggered()));
QAction *deleteTorrentsAct = menu.addAction(
GuiIconProvider::instance()->getIcon("edit-delete")
, tr("Delete torrents"));
connect(deleteTorrentsAct, SIGNAL(triggered()), SIGNAL(actionDeleteTorrentsTriggered()));
menu.exec(QCursor::pos());
}
void CategoryFilterWidget::callUpdateGeometry()
{
updateGeometry();
}
QSize CategoryFilterWidget::sizeHint() const
{
#ifdef QBT_USES_QT5
return viewportSizeHint();
#else
int lastRow = model()->rowCount() - 1;
QModelIndex last = model()->index(lastRow, 0);
while ((lastRow >= 0) && isExpanded(last)) {
lastRow = model()->rowCount(last) - 1;
last = model()->index(lastRow, 0, last);
}
const QRect deepestRect = visualRect(last);
if (!deepestRect.isValid())
return viewport()->sizeHint();
return QSize(header()->length(), deepestRect.bottom() + 1);
#endif
}
QSize CategoryFilterWidget::minimumSizeHint() const
{
QSize size = sizeHint();
size.setWidth(6);
return size;
}
void CategoryFilterWidget::rowsInserted(const QModelIndex &parent, int start, int end)
{
QTreeView::rowsInserted(parent, start, end);
// Expand all parents if the parent(s) of the node are not expanded.
QModelIndex p = parent;
while (p.isValid()) {
if (!isExpanded(p))
expand(p);
p = model()->parent(p);
}
updateGeometry();
}
QString CategoryFilterWidget::askCategoryName()
{
bool ok;
QString category = "";
bool invalid;
do {
invalid = false;
category = AutoExpandableDialog::getText(
this, tr("New Category"), tr("Category:"), QLineEdit::Normal, category, &ok);
if (ok && !category.isEmpty()) {
if (!BitTorrent::Session::isValidCategoryName(category)) {
QMessageBox::warning(
this, tr("Invalid category name")
, tr("Category name must not contain '\\'.\n"
"Category name must not start/end with '/'.\n"
"Category name must not contain '//' sequence."));
invalid = true;
}
}
} while (invalid);
return ok ? category : QString();
}
void CategoryFilterWidget::addCategory()
{
const QString category = askCategoryName();
if (category.isEmpty()) return;
if (BitTorrent::Session::instance()->categories().contains(category))
QMessageBox::warning(this, tr("Category exists"), tr("Category name already exists."));
else
BitTorrent::Session::instance()->addCategory(category);
}
void CategoryFilterWidget::addSubcategory()
{
const QString subcat = askCategoryName();
if (subcat.isEmpty()) return;
const QString category = QString(QStringLiteral("%1/%2")).arg(currentCategory()).arg(subcat);
if (BitTorrent::Session::instance()->categories().contains(category))
QMessageBox::warning(this, tr("Category exists")
, tr("Subcategory name already exists in selected category."));
else
BitTorrent::Session::instance()->addCategory(category);
}
void CategoryFilterWidget::removeCategory()
{
auto selectedRows = selectionModel()->selectedRows();
if (!selectedRows.empty() && !isSpecialItem(selectedRows.first())) {
BitTorrent::Session::instance()->removeCategory(
static_cast<CategoryFilterModel *>(model())->categoryName(selectedRows.first()));
updateGeometry();
}
}
void CategoryFilterWidget::removeUnusedCategories()
{
auto session = BitTorrent::Session::instance();
foreach (const QString &category, session->categories())
if (model()->data(static_cast<CategoryFilterModel *>(model())->index(category), Qt::UserRole) == 0)
session->removeCategory(category);
updateGeometry();
}

View File

@@ -0,0 +1,60 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#include <QTreeView>
class CategoryFilterWidget: public QTreeView
{
Q_OBJECT
public:
explicit CategoryFilterWidget(QWidget *parent = nullptr);
QString currentCategory() const;
signals:
void categoryChanged(const QString &categoryName);
void actionResumeTorrentsTriggered();
void actionPauseTorrentsTriggered();
void actionDeleteTorrentsTriggered();
private slots:
void onCurrentRowChanged(const QModelIndex &current, const QModelIndex &previous);
void showMenu(QPoint);
void callUpdateGeometry();
void addCategory();
void addSubcategory();
void removeCategory();
void removeUnusedCategories();
private:
QSize sizeHint() const override;
QSize minimumSizeHint() const override;
void rowsInserted(const QModelIndex &parent, int start, int end) override;
QString askCategoryName();
};

View File

@@ -35,8 +35,9 @@
#include <QPushButton>
#include "ui_confirmdeletiondlg.h"
#include "base/preferences.h"
#include "guiiconprovider.h"
#include "base/utils/misc.h"
#include "base/utils/string.h"
#include "guiiconprovider.h"
class DeletionConfirmationDlg : public QDialog, private Ui::confirmDeletionDlg {
Q_OBJECT
@@ -45,7 +46,7 @@ class DeletionConfirmationDlg : public QDialog, private Ui::confirmDeletionDlg {
DeletionConfirmationDlg(QWidget *parent, const int &size, const QString &name, bool defaultDeleteFiles): QDialog(parent) {
setupUi(this);
if (size == 1)
label->setText(tr("Are you sure you want to delete '%1' from the transfer list?", "Are you sure you want to delete 'ubuntu-linux-iso' from the transfer list?").arg(name));
label->setText(tr("Are you sure you want to delete '%1' from the transfer list?", "Are you sure you want to delete 'ubuntu-linux-iso' from the transfer list?").arg(Utils::String::toHtmlEscaped(name)));
else
label->setText(tr("Are you sure you want to delete these %1 torrents from the transfer list?", "Are you sure you want to delete these 5 torrents from the transfer list?").arg(QString::number(size)));
// Icons

View File

@@ -96,9 +96,9 @@ class downloadFromURL : public QDialog, private Ui::downloadFromURL{
QMessageBox::warning(0, tr("No URL entered"), tr("Please type at least one URL."));
return;
}
close();
emit urlsReadyToBeDownloaded(url_list_cleaned);
qDebug("Emitted urlsReadytobedownloaded signal");
close();
}
void on_cancelButton_clicked() {

View File

@@ -49,7 +49,9 @@ HEADERS += \
$$PWD/search/searchlistdelegate.h \
$$PWD/search/searchsortmodel.h \
$$PWD/cookiesmodel.h \
$$PWD/cookiesdialog.h
$$PWD/cookiesdialog.h \
$$PWD/categoryfiltermodel.h \
$$PWD/categoryfilterwidget.h
SOURCES += \
$$PWD/mainwindow.cpp \
@@ -89,7 +91,9 @@ SOURCES += \
$$PWD/search/searchlistdelegate.cpp \
$$PWD/search/searchsortmodel.cpp \
$$PWD/cookiesmodel.cpp \
$$PWD/cookiesdialog.cpp
$$PWD/cookiesdialog.cpp \
$$PWD/categoryfiltermodel.cpp \
$$PWD/categoryfilterwidget.cpp
win32|macx {
HEADERS += $$PWD/programupdater.h

View File

@@ -57,13 +57,22 @@ GuiIconProvider *GuiIconProvider::instance()
}
QIcon GuiIconProvider::getIcon(const QString &iconId)
{
return getIcon(iconId, iconId);
}
QIcon GuiIconProvider::getIcon(const QString &iconId, const QString &fallback)
{
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
if (m_useSystemTheme) {
QIcon icon = QIcon::fromTheme(iconId, QIcon(IconProvider::getIconPath(iconId)));
QIcon icon = QIcon::fromTheme(iconId);
if (icon.name() != iconId)
icon = QIcon::fromTheme(fallback, QIcon(IconProvider::getIconPath(iconId)));
icon = generateDifferentSizes(icon);
return icon;
}
#else
Q_UNUSED(fallback)
#endif
return QIcon(IconProvider::getIconPath(iconId));
}
@@ -81,6 +90,13 @@ QIcon GuiIconProvider::getFlagIcon(const QString &countryIsoCode)
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
QIcon GuiIconProvider::generateDifferentSizes(const QIcon &icon)
{
// if icon is loaded from SVG format, it already contains all the required sizes and we shall not resize it
// In that case it will be available in the following sizes:
// (QSize(16, 16), QSize(22, 22), QSize(32, 32), QSize(48, 48), QSize(64, 64), QSize(128, 128), QSize(256, 256))
if (icon.availableSizes(QIcon::Normal, QIcon::On).size() > 6)
return icon;
QIcon newIcon;
QList<QSize> requiredSizes;
requiredSizes << QSize(16, 16) << QSize(24, 24) << QSize(32, 32);

Some files were not shown because too many files have changed in this diff Show More