Compare commits

..

212 Commits

Author SHA1 Message Date
sledgehammer999
13210b3e9f Bump to 4.0.3 2017-12-17 23:31:59 +02:00
sledgehammer999
6e622fc23b Sync translations from Transifex and run lupdate. 2017-12-17 23:19:17 +02:00
Vladimir Golovnev (Glassez)
ae35111b59 Fix WebUI is not reachable via IPv6 2017-12-17 23:07:59 +02:00
Chocobo1
e1c3d419a7 Disable the "?" help button in all dialogs on Windows. Closes #7365. 2017-12-17 23:07:58 +02:00
Chocobo1
7396b8adba Partial revert eac8838dc2. Fixes #7952.
mapFromSource() didn't work as expected, when used in lessThan(), it sometimes
returns an invalid QModelIndex.
A crash is observed when filtering source model via filterAcceptsRow() in #7952,
the crash is due to endless recursive of filterAcceptsRow() & lessThan() calling
each other and mapFromSource() is the culprit of it.
2017-12-17 23:07:57 +02:00
Chocobo1
c09001545d Allow to drag-n-drop URLs into mainwindow to initiate download
Fix issue: https://github.com/qbittorrent/qBittorrent/issues/7785#issuecomment-347092418
Minor refactor
2017-12-17 23:07:55 +02:00
Chocobo1
f8d4315f7e [WebUI] Use POST for logout command
This is to avoid browser being smart to prefetch the link then logging
out the user.
2017-12-17 23:07:54 +02:00
Chocobo1
1fa2957d27 [WebUI] Add check to avoid type error after logout 2017-12-17 23:07:53 +02:00
Chocobo1
ade50d2b53 Fix missing qbt logo on login page in webUI. Closes #7953. 2017-12-17 23:07:52 +02:00
sledgehammer999
0fa1d35b87 Add height padding to the transfer list icons. Closes #7951. 2017-12-17 23:07:29 +02:00
sledgehammer999
6486fc5f4d Bump to 4.0.2 2017-12-01 01:59:53 +02:00
sledgehammer999
1e059ab1a2 Sync translations from Transifex and run lupdate. 2017-12-01 01:44:49 +02:00
Mike Tzou
15b137211b [GUI] Implement stable sort (#7703)
* NaturalCompare now returns compare result instead of "less than" result
* Change to stable sort in GUI components
* Add Utils::String::naturalLessThan() helper function
* Use Qt::CaseSensitivity type
2017-12-01 01:39:16 +02:00
thalieht
6f8f1d7bad Coding style for many files 2017-12-01 01:39:15 +02:00
sledgehammer999
a31f0c0a3d Stop logging IP filter parsing errors after a while.
When a lot of errors happen the resulting log lines introduce
a huge slowdown of the GUI, due to writing each log line to disk.

Closes #7755.
2017-12-01 01:39:08 +02:00
Evgeny Lensky
f977d1293a Fix i386 build (configure)
Fix building on i686 fails with wrong multilib library path #7845

and rebregenerate ./configure
2017-11-27 19:16:03 +02:00
sledgehammer999
1399be50cb Fix crash on some systems when creating address object for 255.255.255.255
Closes #7735.
2017-11-27 19:14:41 +02:00
Vladimir Golovnev (Glassez)
52dcf32cc8 Implement Import/Export RSS rules in JSON format 2017-11-27 19:14:40 +02:00
Vladimir Golovnev (Glassez)
52b2b807ab Implement Import/Export RSS rules in legacy format 2017-11-27 19:14:38 +02:00
sledgehammer999
5cf4f00824 Remove examples from gpl.html. Closes #7749. 2017-11-27 19:14:37 +02:00
TheNicker
faa6fad025 Fixed blurry text under Windows by setting DPI awareness to default 2017-11-27 19:14:36 +02:00
Vladimir Golovnev (Glassez)
9f94bbce3a Fix RSS Parser
Closes #7751
Closes #7763
Closes #7768
Closes #7786
2017-11-27 19:14:35 +02:00
Chocobo1
5c49b2486c Change MixedModeAlgorithm default to TCP. Closes #7779.
MixedModeAlgorithm::Proportional will throttle TCP connections when utp
is in use and users is expecting maximum speed no matter what, so now
disable the throttling.
2017-11-27 19:14:34 +02:00
thoradia
4f6e7f97c6 Fix missing include in rss_feed.cpp
Fixes #7805.
2017-11-27 19:14:33 +02:00
sledgehammer999
7751c5b75c Merge pull request #7835 from heirecka/v4_0_x
Fix build with --disable-webui
2017-11-23 01:50:21 +02:00
Heiko Becker
a1a9f3317b Fix build with --disable-webui
"app/application.cpp:108:7: error: class 'Application' does not have
any field named 'm_webui'"
2017-11-22 21:30:08 +01:00
sledgehammer999
fb20f59a96 Bump to 4.0.1 2017-11-22 01:18:04 +02:00
sledgehammer999
a15e3407b0 Bump API_VERSION to 16. 2017-11-22 01:14:58 +02:00
sledgehammer999
e267c2d37a Sync translations from Transifex and run lupdate. 2017-11-22 01:05:19 +02:00
sledgehammer999
ae32edeb26 Correctly check if torrent passed during application start already exists. 2017-11-22 01:05:18 +02:00
Chocobo1
34d38ef466 Fix crash when aborting a torrent creation process. Closes #7783.
The wait time wasn't long enough causing the thread to
terminate prematurely.
Also, to avoid crashing qbt entirely when creating a torrent for a very
big file, I decided to wait indefinitely here.
2017-11-22 01:05:17 +02:00
Chocobo1
120ee6b836 Wrap function into anonymous namespace 2017-11-22 01:05:15 +02:00
Chocobo1
7d25b6fce2 Avoid double delete on close 2017-11-22 01:05:14 +02:00
Chocobo1
068eff9e9f Use Qt5 connect syntax 2017-11-22 01:05:13 +02:00
Chocobo1
31a55f79f1 Remove superfluous QString::fromUtf8() 2017-11-22 01:03:41 +02:00
Chocobo1
bac032e01c Allow drag-n-drop magnet links to mainwindow. Closes #7742. 2017-11-22 01:03:40 +02:00
sledgehammer999
b809941f02 Fix english typo. 2017-11-22 01:03:39 +02:00
Chocobo1
77c3758090 [WebUI] Fix logo missing in login page 2017-11-22 01:03:37 +02:00
luigino
5758817189 qtsingleapplication should always be built statically to avoid dependency problems 2017-11-20 22:48:56 +02:00
Thomas Piccirello
acc9f08a05 Remove duplicate header 2017-11-20 22:48:55 +02:00
Thomas Piccirello
f3b7f17a7c Enable preferences Apply button when ip banlist is modified 2017-11-20 22:48:54 +02:00
Thomas Piccirello
dfc3f047e2 Add ip subnet whitelist for bypassing webui auth 2017-11-20 22:48:53 +02:00
sledgehammer999
223ab7de84 Fix crash on opening torrent/magnet (uninitialized pointer). Closes #7739 #7723. 2017-11-20 22:48:52 +02:00
sledgehammer999
d2a4027347 Improve the github issue template. 2017-11-20 22:48:37 +02:00
sledgehammer999
4594895082 Bump to 4.0.0 2017-11-20 02:43:03 +02:00
sledgehammer999
e457223fcd Update Changelog. 2017-11-20 02:31:42 +02:00
sledgehammer999
8fc25c4524 Sync translations from Transifex and run lupdate. 2017-11-20 02:24:02 +02:00
sledgehammer999
410e133592 Use new logo in the file icon. 2017-11-20 02:10:03 +02:00
sledgehammer999
e114bc7ef6 Use new logo in the splash screen. 2017-11-20 02:10:02 +02:00
sledgehammer999
6ac57cb24c Remove unused image. 2017-11-20 02:10:01 +02:00
sledgehammer999
2b7893adc8 Use the SVG for the tray icon. 2017-11-20 02:10:00 +02:00
sledgehammer999
84b8832d57 Change qbittorrent logo. Issue #6467. 2017-11-20 02:09:59 +02:00
Vladimir Golovnev (Glassez)
0e738b534c Fix WebUI error handling 2017-11-20 02:09:58 +02:00
Chocobo1
96ce8690b6 Simplify AX_BOOST_BASE usage
Regenerate configure
2017-11-20 02:09:57 +02:00
Chocobo1
a23698940c Sync m4 macros with upstream 2017-11-20 02:09:56 +02:00
Chocobo1
50bb733293 [WebAPI] Improve error messages
Also refactor to use class methods
2017-11-20 02:09:55 +02:00
Vladimir Golovnev (Glassez)
6420157b55 Improve RSS events logging
Fix RSS log messages was untranslatable.
Add more logging.
2017-11-20 02:09:54 +02:00
Eugene Shalygin
86bdfbf88c Add option to tune download history list length. Closes #4043. 2017-11-20 02:09:53 +02:00
Eugene Shalygin
81e8f79164 Add maxVisibleItems combo box property to FileSystemPathComboEdit. 2017-11-20 02:09:52 +02:00
Chocobo1
64a0ad33c1 Include/print caught signal in stackdump 2017-11-20 02:09:51 +02:00
Nikolay Korotysh
3cd0ffecaf dropped unneeded executable flag from several files 2017-11-20 02:09:50 +02:00
sledgehammer999
a2ddabaedb Bump API_VERSION to 16. 2017-11-20 02:09:49 +02:00
sledgehammer999
1fec1978aa Update Changelog. 2017-11-20 02:09:48 +02:00
Chocobo1
8de67fd745 Refactor
Add const
Use Qt5 connect syntax
2017-11-20 02:09:47 +02:00
Chocobo1
3b51582416 Explicitly set UPnP state on start-up. Closes #7338.
libtorrent 1.1 enables upnp by default.
2017-11-20 02:09:46 +02:00
sledgehammer999
ffa2fdce9d Change default settings for tracker/tier announces to mimick ìTorrent behavior. 2017-11-20 02:09:45 +02:00
sledgehammer999
588f1c7592 Allow to specify if announcing to all tiers is desired. 2017-11-20 02:09:44 +02:00
Chocobo1
ab1ece2460 Open links in browser. Closes #7651. 2017-11-20 02:09:43 +02:00
sledgehammer999
7a935d8a87 Add Turkish translator in about page. 2017-11-20 02:09:42 +02:00
Chocobo1
3926eba585 Allow SMTP sender to be set. Closes #7575. 2017-11-20 02:09:41 +02:00
Chocobo1
74bf420610 Disable processing events when adding torrents. Closes #7436.
webUI connection timeout & deletion might occur while
doing processEvents() and will result in use-after-free segfault.
2017-11-20 02:09:39 +02:00
Chocobo1
324f18a0b2 [WebUI] Improve log messages 2017-11-20 02:09:38 +02:00
sledgehammer999
c134e391e6 Run lupdate again. 2017-11-20 02:09:37 +02:00
sledgehammer999
24504951b0 Mention more translators in the about page after their request. 2017-11-20 02:09:35 +02:00
sledgehammer999
f7f02ab16a String fixes and optimizations mentioned by translators on Transifex. 2017-11-20 02:09:29 +02:00
sledgehammer999
fe810fcd37 Revert "Update Transifex config file."
This reverts commit e872719ef1.
2017-10-24 01:31:06 +03:00
sledgehammer999
17167e79d2 Sync translations from Transifex and run lupdate. 2017-10-24 01:31:04 +03:00
Chocobo1
7bd86048a8 WebAPI refactor: utilize parseBool() function
Coding style cleanup
Rename variable
Return const reference
Add const
2017-10-24 01:30:37 +03:00
Chocobo1
d399f024a7 Reinitialize webUI server when "IP address" setting changed
An app restart won't be necessary from now on.
2017-10-24 01:30:36 +03:00
sledgehammer999
21f06abef8 Fix row height/width in webui for country flags.
Patch by Chocobo1.
2017-10-24 01:07:57 +03:00
sledgehammer999
fbe0e96fd5 Use svg icons for the country flags.
Closes #6223.
2017-10-24 01:07:55 +03:00
Matthew Fioravante
94e00dd38d Add WebUi\Address config option 2017-10-24 01:07:54 +03:00
Chocobo1
c3f5432877 [WebUI]: Print error messages upon receiving invalid header fields 2017-10-24 01:07:53 +03:00
dzmat
4dcc187a72 speedwidget class: excess QtConcurent usage removal 2017-10-24 01:07:51 +03:00
scootergrisen
97c99dfaaf Add me for danish 2017-10-24 01:07:50 +03:00
sledgehammer999
da83041a3f Generate pngs using svgexport and optimize using PNGGauntlet. 2017-10-24 01:07:49 +03:00
sledgehammer999
d40a4f14dd Optimize and prettify the svg source using svgo. 2017-10-24 01:07:48 +03:00
LordNyriox
de7b0278f4 Invert Framing for Torrent Status Icons
Also recolor the icons to match the text-color used for the torrent-status as well. 
Optimized using SVGOMG [<https://jakearchibald.github.io/svgomg/>].
2017-10-24 01:07:47 +03:00
Chocobo1
17f5e10ffc Convert tab into whitespaces 2017-10-24 01:07:45 +03:00
Chocobo1
a0dbb6c97c WebUI: add optional parameters for /command/download & /command/upload
Specifically:
torrent name: string
download limit, upload limit: number in bytes, default: -1 (unlimited)
sequential download, first last piece prio: boolean true/false, default: false
2017-10-24 01:07:44 +03:00
Chocobo1
4d330a6110 Add uploadLimit, downloadLimit fields to AddTorrentData & AddTorrentParams 2017-10-24 01:07:43 +03:00
Chocobo1
9fc2bf6353 Add file-to-piece-index mappings in /query/propertiesFiles command
Also do the following cleanups:
  Use string constant QB_EXT
  Remove redundant variable
  Add const
2017-10-24 01:07:42 +03:00
sledgehammer999
f9c7121847 Sync translations from Transifex and run lupdate. 2017-10-24 01:07:31 +03:00
Eugene Shalygin
d3a0ac3b6e Make BitTorrent::TorrentState strongly-typed enum
This is needed to forward declare this type and pass it by value.

Conversion from/to QVariant are hanled via Q_DECLARE_METATYPE, while
TorrentState::toString() function was used in webui only and as such is
moved there.
2017-10-24 00:57:58 +03:00
Tim Delaney
a6c99844de Follow project coding style. Issue #2192.
--HG--
branch : magao-dev
2017-10-24 00:57:57 +03:00
Chocobo1
d51a957247 Die gracefully when failed to initialize web server with qbt-nox 2017-10-24 00:57:56 +03:00
Matthew Fioravante
a0c16cd461 Report TCPServer errorString() if webui fails to listen to port 2017-10-24 00:57:55 +03:00
Chocobo1
8fe11dff91 Fix delete key has no effect due to "Ambiguous shortcut overload"
We want to show the accelerator key in the menu but without hitting
the ambiguous overload error.
Fixup of 1378245a63
2017-10-24 00:57:54 +03:00
Eugene Shalygin
efcdcf5898 Update uncrustify config 2017-10-24 00:57:52 +03:00
sledgehammer999
da543cdae2 Optimize SVGs.
Used svgo with commands --pretty --indent=2 --multipass.
2017-10-24 00:55:41 +03:00
sledgehammer999
0374742e57 Optimize PNGs.
Using PNGGauntlet.
2017-10-24 00:55:39 +03:00
sledgehammer999
408052d1ec Remove unused image. Possibly leftover from dropping Qt4. 2017-10-24 00:55:38 +03:00
sledgehammer999
b0ebbc3596 Drop OS/2 support. 2017-10-24 00:55:37 +03:00
sledgehammer999
e45e1166b2 Show new paths in native form. 2017-10-24 00:55:35 +03:00
thalieht
de64d5c3bc Save ratio limits as int instead of string 2017-10-24 00:55:34 +03:00
thalieht
07130c4b26 Coding style, use nullptr and other minor things 2017-10-24 00:55:33 +03:00
thalieht
8482464ad0 Properly pre-select the selected torrent's current ratio limiting options in UpDownRatioDlg dialogs. Fixes #7352 2017-10-24 00:55:32 +03:00
Eugene Shalygin
d7ce6e39d4 cmake: do not use Qt5Widgets when locating QtSingleApplication. Closes #7551.
This fixes cmake builds with GUI disabled and system
QtSingleApplication. We rely on Qt5::Core instead of Qt5::Widgets.
2017-10-24 00:55:30 +03:00
Chocobo1
97acbd5259 Set QTextOption::NoWrap property in "Download from URLs" dialog
This makes it easier to put each magnet link on its own line
2017-10-24 00:55:29 +03:00
Nick Korotysh
60937a1871 show delete accelerator key in menu. closes #7508 2017-10-24 00:55:28 +03:00
Nick Korotysh
ed43bc377d allow search plugins sorting. closes #7526 2017-10-24 00:55:27 +03:00
Vladimir Golovnev (Glassez)
8d11929815 Reformat Windows build configuration files 2017-10-24 00:55:26 +03:00
dzmat
0e6f8c15c5 transferlistwidget class members names clarification 2017-10-24 00:55:24 +03:00
Chocobo1
8107201a5b Fix "Time active" field in transfer list
The "Time active" field was broken, displaying nothing when in
downloading state.
Also change type to int to match the return
types of TorrentHandle::activeTime() & TorrentHandle::seedingTime()
2017-10-24 00:55:23 +03:00
Vladimir Golovnev (Glassez)
395ea4d1d0 Implement TorrentCategoryDialog class 2017-10-24 00:55:22 +03:00
Vladimir Golovnev (Glassez)
7bf317929b Use Qt5 connect() style in CategoryFilterWidget 2017-10-24 00:55:21 +03:00
Chocobo1
3cacf876c9 Show torrent name in "add new torrent" dialog on merging trackers 2017-10-24 00:55:20 +03:00
silver
d6247dd4ec Center Options dialog when showed 2017-10-24 00:53:10 +03:00
silver
4f0c49f1c4 Persist size and treeview header state in preview dialog
- renamed variable m_headerState
 - renamed PreviewSelect class to PreviewSelectDialog
 - renamed previewselect files to previewselectdialog
2017-10-24 00:53:09 +03:00
silver
30455e8b01 Follow project coding style. Issue #2192. 2017-10-24 00:53:08 +03:00
silver
60adb94463 Options dialog save windows state in destructor 2017-10-24 00:53:07 +03:00
Chocobo1
a02fd5b588 Fix last activity calculation. Closes #7461
`time_since_upload` & `time_since_download` can be -1, so filter them out
2017-10-24 00:53:06 +03:00
sledgehammer999
39ce080318 Don't use margins in FileSystemPathEdit widgets.
Introduced in 30081e0.
2017-10-24 00:53:04 +03:00
Chocobo1
f53abd2f07 Update qtsingleapplication
To upstream version a8dda66d7738cde9042b87db27993f710ae3eeeb
2017-10-24 00:53:03 +03:00
Thomas Piccirello
5b0ae0271b Reposition "Priority" menu option in WebUI to match gui (closes #7072) 2017-10-24 00:53:02 +03:00
sledgehammer999
ec2efd8c62 Better reporting of success/failure of torrent and file deletion. 2017-10-24 00:53:01 +03:00
Chocobo1
146daea513 Replace dialog ok-cancel buttons with QDialogButtonBox
This PR will make button order follow the platform default.
For example: windows use: OK, Cancel; linux use: Cancel, OK.
2017-10-24 00:53:00 +03:00
Chocobo1
5ab67faacb Use smaller data type for TriStateBool 2017-10-24 00:52:58 +03:00
Chocobo1
4213d37857 WebAPI: fix addPaused wrong default behavior
Add helper function
Sort include header
2017-10-24 00:52:57 +03:00
Chocobo1
0192922910 Refactor
Merge statements
Use case-insensitive contains()
Add const
Use value(), this avoids inserting empty values.
Use range based for loop
2017-10-24 00:52:56 +03:00
Chocobo1
d2b88e9f84 WebAPI: fix root_folder default behavior
Bug was introduced in
6b33db3ae3
2017-10-24 00:52:55 +03:00
Chocobo1
a32c4aca92 Add comboBox for selecting BitTorrent protocol. Closes #6316.
Use unicode string C_UTP in place of "uTP"
2017-10-24 00:52:54 +03:00
thalieht
91d41336a7 Create root folder option when adding a torrent in WebUI 2017-10-24 00:52:53 +03:00
Chocobo1
d73d790612 Rename option
The previous "Disk write cache size" is not accurate since it is also being used
for read cache, so rename it to "Disk cache".
2017-10-24 00:52:51 +03:00
Chocobo1
af0fed6669 Change default value of m_diskCacheSize. New default is 64 MB. 2017-10-24 00:52:50 +03:00
Eugene Shalygin
a24c13b902 Allow custom tray icons when system icon theme is used. Closes #7403. 2017-10-24 00:52:49 +03:00
Chocobo1
c44c6a8d88 Fix dereferencing freed pointer. Closes #7420.
The torrent is removed from session after `deleteTorrent()`
yet we still invoke `torrent->name()`, thus result in crash.
2017-10-24 00:52:48 +03:00
sledgehammer999
5f62a68e71 Travis: Update libtorrent bottle with boost 1.65+ fix. 2017-10-24 00:52:41 +03:00
Allan Nordhøy
5af90fee46 Spelling: HTTP/HTTPS 2017-10-23 19:03:40 +03:00
Chocobo1
b17566f113 Update coding guidelines
Add ranged-based for loop example
Add class inheritance example
Add Prefer pre-increment, pre-decrement operators section
Fix space after comment keyword
Fix header include order
[skip ci]
2017-10-23 19:03:39 +03:00
sledgehammer999
29edea050b Update Changelog. 2017-10-23 19:03:38 +03:00
sledgehammer999
7ceb646e90 Bump to 3.4.0beta2 2017-10-23 19:03:37 +03:00
sledgehammer999
0ff39e4d10 Sync translations from Transifex and run lupdate. 2017-10-23 19:02:44 +03:00
sledgehammer999
1e146c94bd Fix file list expansion on singlefile torrent with folder. 2017-10-23 18:12:43 +03:00
Vladimir Golovnev
8a0da04807 Fix CategoryFilterWidget::sizeHint() 2017-10-23 18:12:42 +03:00
Vladimir Golovnev
9e7a847cce Fix suggest_mode setting
Actually suggest_mode is of type int.
2017-10-23 18:12:41 +03:00
Chocobo1
63d3f20e51 Sort the resource lists
Update RCC header
2017-10-23 18:12:40 +03:00
Chocobo1
817e3fbb05 Cleanup src.pro 2017-10-23 18:12:39 +03:00
Chocobo1
263e96aba2 Move NOMINMAX define 2017-10-23 18:12:37 +03:00
Chocobo1
0379376fd8 Define QT_USE_QSTRINGBUILDER.
The old defines are deprecated.
QT_USE_QSTRINGBUILDER also supports QByteArray which we use extensively
in WebUI.
2017-10-23 18:12:36 +03:00
Chocobo1
de7efb50c2 Use Qt5 connect syntax 2017-10-23 18:12:35 +03:00
Chocobo1
400f8dc2d8 Setup parent ownership to avoid memory leak 2017-10-23 18:12:34 +03:00
Chocobo1
b2b63be798 Use enums for settings 2017-10-23 18:12:33 +03:00
Chocobo1
c9aba893de Add sanitize helper clampValue() 2017-10-23 18:12:32 +03:00
Chocobo1
1ac4cdcf4d Add send_buffer_watermark send_buffer_low_watermark
send_buffer_watermark_factor knobs
2017-10-23 18:12:30 +03:00
Chocobo1
08a0fef18a Add suggest_mode knob 2017-10-23 18:12:29 +03:00
Chocobo1
6f54c170ab Add choking_algorithm & seed_choking_algorithm knob 2017-10-23 18:12:28 +03:00
Chocobo1
d3b4c7bec4 Add allow_multiple_connections_per_ip knob. Closes #5884. 2017-10-23 18:12:27 +03:00
Chocobo1
f8dfe1ea57 Add mixed_mode_algorithm knob 2017-10-23 18:12:26 +03:00
Chocobo1
ce5f8bab44 Add guided_read_cache knob
cleanup header include order
2017-10-23 18:12:24 +03:00
Vladimir Golovnev
59cf70f8f2 Fix RSS Downloader fails to rename rule
Closes #7333.
2017-10-23 18:12:23 +03:00
Vladimir Golovnev (qlassez)
561975f435 Improve BandwidthScheduler
Don't disable scheduler when manually switching speed limits.
Closes #7306.
2017-10-23 18:12:22 +03:00
Vladimir Golovnev
eae6fea830 Skip user input events when adding torrent
Closes #7327.
2017-10-23 18:12:21 +03:00
Evengard
2673c2b5b2 Disable skipping of loopback interfaces
This fixes the absence of VPN tunnel interfaces under Windows and works around the QTBUG-32349
Fixes #7291
2017-10-23 18:12:20 +03:00
Eugene Shalygin
3c17f3a836 Fix ignoring of incorrect version strings in search plugins. Closes #7101.
Printing of Version with all components set to zero was segfaulting due
to underflow in array index. Also add log message for such plugins.
2017-10-23 18:12:19 +03:00
Chocobo1
0890154e16 WebAPI: fix validating wrong header field. Closes #7311.
X-Forwarded-Host is a foreign proxy setting, it isn't the same as
qbt's local setting and thus it makes no sense to verify it.
2017-10-23 18:12:17 +03:00
sledgehammer999
0877824875 Check for Qt5Svg when configuring. 2017-10-23 18:12:16 +03:00
Chocobo1
60bd5999b0 Wrap class & functions in anonymous namespace
Rename vars
Cleanup class interfaces
Pass by reference whenever possible
2017-10-23 18:12:15 +03:00
sledgehammer999
d0ec60fa01 Switch settings to signed int because libtorrent expects them that way. 2017-10-23 18:12:14 +03:00
sledgehammer999
e7a70a4acc Options to better memory control by libtorrent. Closes #7029. 2017-10-23 18:12:13 +03:00
Eugene Shalygin
85cb49e8e1 Use pixmap cache for file icons on Mac OS and Windows. Closes #7264. 2017-10-23 18:12:12 +03:00
Vladimir Golovnev (qlassez)
3f00a6e5e3 Improve utils/fs.* and fix coding style 2017-10-23 18:12:10 +03:00
vit9696
35e18a2e09 Fix notification display on macOS 2017-10-23 18:12:09 +03:00
sledgehammer999
8ae2ae3b5c Fix broken build. 2017-10-23 18:12:08 +03:00
vit9696
27c5f2aede Fix macOS window restoration after using hide icon 2017-10-23 18:12:07 +03:00
sledgehammer999
34a69aa0b2 Use simpler ifdef style. 2017-10-23 18:12:06 +03:00
Brian Kendall
72fc903f4a Fixed mac specific compiler errors and cleaned up Objective C code
Created new file src/gui/macutilities.mm, moved code from mainwindow.cpp and torrentcontentmodel.cpp that used the Objective C runtime into it and converted it to actual Objective C. Rewrote pixmapForExtension() so that it doesn't call into private Qt functions.
2017-10-23 18:12:05 +03:00
sledgehammer999
4f04992de8 Fix connection problems when a specific interface/ip is configured.
Closes #7235.
Bug related to #7099 and Qt.
2017-10-23 18:12:04 +03:00
vit9696
1b147494d4 Unify preference window borders across the tabs 2017-10-23 18:12:02 +03:00
sledgehammer999
b535a0b44e Fix calculation of 'Average time in queue' stat under libtorrent 1.1.x 2017-10-23 18:12:01 +03:00
Thomas Piccirello
6c2271584c Use single quotes for char.
Use case insensitive compare.
Swap conditionals
2017-10-23 18:12:00 +03:00
Thomas Piccirello
1002b28c95 Add auto torrent management to webui context menu (addresses #6815) 2017-10-23 18:11:54 +03:00
Chocobo1
dfded7bc9d Add space between widgets in left side panel. Closes #7224. 2017-10-23 02:11:55 +03:00
sledgehammer999
36fde9ede5 Error out in configure script if the proper Qt/qmake version isn't found.
Closes #7250.
Partially reverts e64bb1de8c.
2017-10-23 02:11:54 +03:00
Chocobo1
6b4ac1b960 Initialize variables
Remove unused variable
2017-10-23 02:11:53 +03:00
Thomas Piccirello
cc141ba02f Add option to rename torrent from WebUI
Addresses #6815.
2017-10-23 02:11:52 +03:00
Vladimir Golovnev (qlassez)
8fc931a61b Use qUtf8Printable() for logging strings
qDebug(), qInfo(), qWarning(), qCritical(), qFatal() expect %s arguments
to be UTF-8 encoded, while qPrintable() converts to local 8-bit encoding.
Therefore qUtf8Printable() should be used for logging strings instead of
qPrintable().
2017-10-23 02:11:51 +03:00
Vladimir Golovnev (qlassez)
0b6cf54508 Don't remove shared temp folder
Don't remove shared temp folder when torrent finished and moved to
its "complete" folder. Only torrents with stripped root folder
have subfolder in temp folder so they should remove it.
2017-10-23 02:11:50 +03:00
sledgehammer999
ff12163176 Follow project coding style. 2017-10-23 02:11:49 +03:00
sledgehammer999
6a8a0bbd6b Catch possible exceptions when parsing IPs. Closes #7249. 2017-10-23 02:11:47 +03:00
sledgehammer999
f8ebffac65 Use dpiawareness=1 on Windows. Closes #5393. 2017-10-23 02:11:46 +03:00
Vladimir Golovnev (qlassez)
e58f4c0bdf Remove legacy RSS settings after converting
Closes #7226.
2017-10-23 02:11:45 +03:00
thalieht
f450ff278d Remove indentation for category/tag filter widgets in all platforms 2017-10-23 02:11:44 +03:00
Chocobo1
566fd893f4 Prefill torrent name when creating a new torrent. Closes #7229. 2017-10-23 02:11:43 +03:00
sledgehammer999
30ab46999c Fix explicit Torrent Management Mode in Add New Torrent dialog. Closes #5602. 2017-10-23 02:11:35 +03:00
sledgehammer999
0320f9d5b5 Update Changelog. 2017-08-07 08:55:30 +03:00
sledgehammer999
ad7c9ed123 Bump to 3.4.0beta 2017-08-07 08:40:22 +03:00
sledgehammer999
25acdba344 Sync translations from Transifex and run lupdate. 2017-08-07 08:38:09 +03:00
Chocobo1
786059802b Correctly handle translation
Fixup of 07a85a1018
2017-08-07 08:27:09 +03:00
Chocobo1
0ae708114b Move "Copy hash" menu item above "Copy magnet link"
Fix wrong "Copy hash" icon used in webUI
Fixup of 145641ac41
2017-08-07 08:27:08 +03:00
vit9696
fbeaabb841 Fix file type icons not displaying on macOS 2017-08-07 08:27:07 +03:00
Tom Piccirello
98bef605a7 Set torrent location from webui context menu (addresses #6815) (#7062)
* Add option to set torrent location from webui context menu (addresses #6815)

* Update debug messages

* Use logger

* Remove redundant curly braces

* Remove message

* Use log message from transferlistwidget

* Use QDir

* Remove unused import

* Check if newLocation is an empty string
2017-08-07 08:27:05 +03:00
Tom Piccirello
37a0e48b46 Add copy options to webui context menu (addresses #6815) (#7036)
* Add copy options to webui context menu
Add Copy Hash to gui (closes #6964)

* Use switch statement

* Use camel case, switch from signal to qaction.

* Rename variable

* Change variable name
2017-08-07 08:27:04 +03:00
sledgehammer999
fea1a66aba Fix some more strings. 2017-08-07 08:27:03 +03:00
Allan Nordhøy
0ffdb51f95 display, URLs, esc ' 2017-08-07 08:27:01 +03:00
Vladimir Golovnev (qlassez)
4e596629fd Don't replace existing files when relocating torrent 2017-08-07 08:27:00 +03:00
Vladimir Golovnev (qlassez)
61281dd226 Don't remove shared temp folder 2017-08-07 08:26:59 +03:00
Vladimir Golovnev (Glassez)
61d1f2180f Don't create subfolder inside temp folder 2017-08-07 08:26:58 +03:00
vlakoff
3bcf941205 Windows installer: also detect running process when it is 64-bit
Replacing FindProcDLL with a different one that can be found here:

http://forums.winamp.com/showthread.php?t=322583#post2777719
2017-08-07 08:26:56 +03:00
Tony Gregerson
1746c9d331 Improve checkbox interface for selecting tags in the context menu. Closes #7060 2017-08-07 08:26:55 +03:00
Vladimir Golovnev (Glassez)
58c31c5353 Fix temporary subfolder isn't deleted 2017-08-07 08:26:47 +03:00
sledgehammer999
e872719ef1 Update Transifex config file. 2017-07-27 19:19:10 +03:00
792 changed files with 158662 additions and 303716 deletions

View File

@@ -45,7 +45,8 @@ before_build:
- CALL "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat"
- SET PATH=%PATH%;c:\qbt\qt5_32\bin;%CACHE_DIR%\jom;
# setup project
- COPY /Y "%CACHE_DIR%\conf.pri" "%REPO_DIR%"
- COPY /Y "%CACHE_DIR%\winconf.pri" "%REPO_DIR%"
- COPY /Y "%CACHE_DIR%\winconf-msvc.pri" "%REPO_DIR%"
# workarounds
- MKLINK /J "c:\qbt\base" "%CACHE_DIR%\base"

1
.gitignore vendored
View File

@@ -22,7 +22,6 @@ qrc_*.cpp
ui_*.h
*.moc
src/lang/qbittorrent_*.qm
src/webui/www/translations/webui_*.qm
.DS_Store
.qmake.stash
src/qbittorrent.app

View File

@@ -3,8 +3,7 @@ language: cpp
os:
- linux
- osx
dist: xenial
osx_image: xcode7.3
env:
matrix:
@@ -39,6 +38,11 @@ cache:
directories:
- $HOME/hombebrew_cache
# opt-in Ubuntu Trusty
dist: trusty
# container-based builds
sudo: false
addons:
coverity_scan:
project:
@@ -50,31 +54,32 @@ addons:
notification_email: sledgehammer999@qbittorrent.org
apt:
sources:
# sources list: https://github.com/travis-ci/apt-source-safelist/blob/master/ubuntu.json
# sources list: https://github.com/travis-ci/apt-source-whitelist/blob/master/ubuntu.json
- ubuntu-toolchain-r-test
#- boost-latest
- sourceline: 'ppa:qbittorrent-team/qbittorrent-stable'
- sourceline: 'ppa:beineri/opt-qt551-trusty'
- sourceline: 'ppa:adrozdoff/cmake'
packages:
# packages list: https://github.com/travis-ci/apt-package-safelist/blob/master/ubuntu-trusty
# packages list: https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise
- [autoconf, automake, colormake]
- [ninja-build]
- [cmake, ninja-build]
- libssl-dev
- [libboost-dev, libboost-system-dev]
- libtorrent-rasterbar-dev
- [qtbase5-dev, qttools5-dev-tools, libqt5svg5-dev]
- [qt55base, qt55svg, qt55tools]
- [gcc-6, g++-6]
before_install:
# only allow specific build for coverity scan, others will stop
- if [ "$TRAVIS_BRANCH" = "$coverity_branch" ] && ! [ "$TRAVIS_OS_NAME" = "linux" -a "$lt_branch" = "RC_1_0" -a "$gui" = true -a "$build_system" = "qmake" ]; then exit ; fi
- shopt -s expand_aliases
- alias make="colormake -j2" # Using nprocs/2 sometimes may fail (gcc is killed by system)
- alias make="colormake -j3" # Using nprocs/2 sometimes may fail (gcc is killed by system)
#- libt_path="$HOME/libt_install"
#- ltconf="$ltconf --prefix="$libt_path" --disable-geoip"
- qbt_path="$HOME/qbt_install"
- |
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
qbtconf="$qbtconf --prefix="$qbt_path" PKG_CONFIG_PATH=/opt/qt55/lib/pkgconfig:$PKG_CONFIG_PATH"
else
qbtconf="$qbtconf --prefix="$qbt_path" PKG_CONFIG_PATH=/usr/local/opt/openssl/lib/pkgconfig:$PKG_CONFIG_PATH"
CXXFLAGS="$CXXFLAGS -Wno-unused-local-typedefs -Wno-inconsistent-missing-override"
fi
- qbtconf="$qbtconf --prefix="$qbt_path" PKG_CONFIG_PATH="$libt_path/lib/pkgconfig":/opt/qt55/lib/pkgconfig:$PKG_CONFIG_PATH"
# options for specific branches
- if [ "$gui" = false ]; then qbtconf="$qbtconf --disable-gui" ; fi
@@ -82,6 +87,14 @@ before_install:
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
# setup virtual display for after_success target
if [ "$gui" = true ]; then export "DISPLAY=:99.0" && /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16 ; fi ;
# Qt 5
PATH=/opt/qt55/bin:${PATH}
if [ "$build_system" = "cmake" ]; then
COMPILER_VERSION=6
export CXX="${CXX}-${COMPILER_VERSION}" CC="${CC}-${COMPILER_VERSION}"
fi
fi
# print settings
@@ -105,24 +118,41 @@ install:
# dependencies
brew update > /dev/null
brew outdated "pkg-config" || brew upgrade "pkg-config"
brew install colormake ccache zlib qt openssl libtorrent-rasterbar
brew install colormake ccache zlib qt
PATH="/usr/local/opt/ccache/libexec:$PATH"
brew link --force zlib qt
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.11+git20170910.6d5625e0ea.el_capitan.bottle.tar.gz
fi
# 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.11+git20170910.6d5625e0ea.el_capitan.bottle.tar.gz" "$(brew --cache)"
brew install "$HOME/hombebrew_cache/libtorrent-rasterbar.rb"
if [ "$build_system" = "cmake" ]; then
brew outdated cmake || brew upgrade cmake
brew install ninja
sudo ln -s /usr/local/opt/qt/mkspecs /usr/local/mkspecs
sudo ln -s /usr/local/opt/qt/plugins /usr/local/plugins
MY_CMAKE_OPENSSL_HINT="-DOPENSSL_ROOT_DIR=/usr/local/opt/openssl/"
ln -s /usr/local/opt/qt/mkspecs /usr/local/mkspecs
ln -s /usr/local/opt/qt/plugins /usr/local/plugins
fi
MY_CMAKE_OPENSSL_HINT="-DOPENSSL_ROOT_DIR=/usr/local/opt/openssl/"
fi
- |
if [ "$TRAVIS_BRANCH" != "$coverity_branch" ]; then
export use_ccache=true
ccache -M 512M
ccache -V && ccache --show-stats && ccache --zero-stats
fi
@@ -133,15 +163,17 @@ script:
if [ "$build_system" = "cmake" ]; then
mkdir build
cd build
if [ "$gui" = "false" ]; then
DISABLE_GUI_OPTION="-DCMAKE_DISABLE_FIND_PACKAGE_Qt5Widgets=ON"
fi
cmake $DISABLE_GUI_OPTION -DCMAKE_INSTALL_PREFIX="$qbt_path" "$MY_CMAKE_OPENSSL_HINT" \
cmake -DGUI=${gui} -DCMAKE_INSTALL_PREFIX="$qbt_path" "$MY_CMAKE_OPENSSL_HINT" \
-G "Ninja" -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=TRUE ..
BUILD_TOOL="ninja"
fi
if [ "$build_system" = "qmake" ]; then
./bootstrap.sh && ./configure $qbtconf CXXFLAGS="$CXXFLAGS"
./bootstrap.sh && ./configure $qbtconf
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
sed -i "" -e "s/^\(CC.*&&\).*$/\1 $CC/" src/Makefile # workaround for Qt & ccache: https://bugreports.qt.io/browse/QTBUG-31034
sed -i "" -e "s/^\(CXX.*&&\).*$/\1 $CXX/" src/Makefile
sed -i "" -e 's/^\(CXXFLAGS.*\)$/\1 -Wno-unused-local-typedefs -Wno-inconsistent-missing-override/' src/Makefile
fi
BUILD_TOOL="make"
fi
- $BUILD_TOOL && $BUILD_TOOL install

View File

@@ -10,18 +10,10 @@ type = QT
minimum_perc = 23
mode = developer
[qbittorrent.qbittorrentdesktop_master]
source_file = dist/unix/org.qbittorrent.qBittorrent.desktop
source_file = src/icons/qBittorrent.desktop
source_lang = en
type = DESKTOP
minimum_perc = 23
mode = developer
[qbittorrent.qbittorrent_webui]
file_filter = src/webui/www/translations/webui_<lang>.ts
lang_map = pt: pt_PT
source_file = src/webui/www/translations/webui_en.ts
source_lang = en
type = QT
minimum_perc = 23
mode = developer

View File

@@ -1,6 +1,5 @@
cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
message(AUTHOR_WARNING "If the build fails, please try the autotools/qmake method.")
cmake_minimum_required(VERSION 3.5)
cmake_policy(VERSION 3.5)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules)
include(FunctionReadVersion)
@@ -26,29 +25,32 @@ add_definitions(-DQBT_VERSION_BUILD=${VER_BUILD})
add_definitions(-DQBT_VERSION="v${PROJECT_VERSION}")
add_definitions(-DQBT_VERSION_2="${PROJECT_VERSION}")
include(GNUInstallDirs)
include(FeatureSummary)
# version requirements
set(requiredBoostVersion 1.35)
set(requiredQtVersion 5.5.1)
if (UNIX AND NOT APPLE)
include(GNUInstallDirs)
endif (UNIX AND NOT APPLE)
if(WIN32)
include(winconf)
endif(WIN32)
# we need options here, because they are used not only in "src" subdir, but in the "dist" dir too
include(CMakeDependentOption)
# we need options here, at the top level, because they are used not only in "src" subdir, but in the "dist" dir too
include(CompileFeature)
option(SYSTEM_QTSINGLEAPPLICATION
"Use the system qtsingleapplication library or shipped one otherwise")
option(GUI "Allows to disable GUI for headless running. Disables QtDBus and the GeoIP Database" ON)
option(WEBUI "Allows to disable the WebUI." ON)
if (WIN32)
option(STACKTRACE_WIN "")
else (WIN32)
cmake_dependent_option(SYSTEMD "Install the systemd service file (headless only)" OFF
"NOT GUI" OFF)
cmake_dependent_option(DBUS "Enable use of QtDBus (GUI only)" ON "GUI" OFF)
endif(WIN32)
optional_compile_definitions(COUNTRIES_RESOLUTION FEATURE DESCRIPTION "Enable resolving peers IP addresses to countries"
DEFAULT ON DISABLED DISABLE_COUNTRIES_RESOLUTION)
optional_compile_definitions(STACKTRACE FEATURE DESCRIPTION "Enable stacktraces"
DEFAULT ON ENABLED STACKTRACE)
optional_compile_definitions(WEBUI FEATURE DESCRIPTION "Enables built-in HTTP server for headless use"
DEFAULT ON DISABLED DISABLE_WEBUI)
add_subdirectory(src)
add_subdirectory(dist)
feature_summary(DESCRIPTION "\nConfiguration results:" WHAT ALL)

View File

@@ -1,38 +1,10 @@
All new code **must** follow the following coding guidelines.
If you make changes in a file that still uses another coding style, make sure that you follow these guidelines for your changes.
For programming languages other than C++ (e.g. JavaScript) used in this repository and submodules, unless otherwise specified, coding guidelines listed here applies as much as possible.
All new code must follow the following coding guidelines.
If you make changes in a file that still uses another coding style, make sure that you follow these guidelines for your changes instead.
**Note 1:** I will not take your head if you forget and use another style. However, most probably the request will be delayed until you fix your coding style.
**Note 2:** You can use the `uncrustify` program/tool to clean up any source file. Use it with the `uncrustify.cfg` configuration file found in the root folder.
**Note 3:** There is also a style for QtCreator but it doesn't cover all cases. In QtCreator `Tools->Options...->C++->Code Style->Import...` and choose the `codingStyleQtCreator.xml` file found in the root folder.
### Table Of Contents
* [1. New lines &amp; curly braces](#1-new-lines--curly-braces)
* [a. Function blocks, class/struct definitions, namespaces](#a-function-blocks-classstruct-definitions-namespaces)
* [b. Other code blocks](#b-other-code-blocks)
* [c. Blocks in switch's case labels](#c-blocks-in-switchs-case-labels)
* [d. If-else statements](#d-if-else-statements)
* [e. Single statement if blocks](#e-single-statement-if-blocks)
* [f. Acceptable conditions to omit braces](#f-acceptable-conditions-to-omit-braces)
* [g. Brace enclosed initializers](#g-brace-enclosed-initializers)
* [2. Indentation](#2-indentation)
* [3. File encoding and line endings](#3-file-encoding-and-line-endings)
* [4. Initialization lists](#4-initialization-lists)
* [5. Enums](#5-enums)
* [6. Names](#6-names)
* [a. Type names and namespaces](#a-type-names-and-namespaces)
* [b. Variable names](#b-variable-names)
* [c. Private member variable names](#c-private-member-variable-names)
* [7. Header inclusion order](#7-header-inclusion-order)
* [8. Include guard](#8-include-guard)
* [9. Misc](#9-misc)
* [10. Git commit message](#10-git-commit-message)
* [11. Not covered above](#11-not-covered-above)
---
### 1. New lines & curly braces ###
### 1. Curly braces ###
#### a. Function blocks, class/struct definitions, namespaces ####
```c++
int myFunction(int a)
@@ -117,8 +89,18 @@ default:
}
```
#### d. If-else statements ####
The `else if`/`else` must be on their own lines:
#### d. Brace enclosed initializers ####
Unlike single-line functions, you must not insert spaces between the brackets and concluded expressions.<br/>
But you must insert a space between the variable name and initializer.
```c++
Class obj {}; // empty
Class obj {expr};
Class obj {expr1, /*...,*/ exprN};
QVariantMap map {{"key1", 5}, {"key2", 10}};
```
### 2. If blocks ###
#### a. Multiple tests ####
```c++
if (condition) {
// code
@@ -130,71 +112,40 @@ else {
// code
}
```
The `else if`/`else` must be on their own lines.
#### e. Single statement if blocks ####
Most single statement if blocks should look like this:
#### b. Single statement if blocks ####
**Most** single statement if blocks should look like this:
```c++
if (condition)
a = a + b;
```
One acceptable exception to this can be `return`, `break` or `continue` statements,
provided that the test condition isn't very long and its body statement occupies only one line.
However you can still choose to use the first rule.
One acceptable exception to this **can be** `return`, `break` or `continue` statements, provided that the test condition isn't very long. However you can choose to use the first rule instead.
```c++
if (a > 0) return;
a = myFunction();
b = a * 1500;
while (p) {
// ...
if (!b) continue;
}
if (b > 0) return;
c = 100 / b;
```
#### f. Acceptable conditions to omit braces ####
When the conditional statement in `if`/`else` has only one line and its body occupy only one line,
this also applies to loops statements.
Notice that for a series of `if - else` branches, if one branch needs braces then all branches must add braces.
```c++
if (a < b) // conditional statement
do(a); // body
#### c. Using curly braces for single statement if blocks ####
if (a < b)
do(a);
else if (a > b)
do(b);
else
do(c);
However, there are cases where curly braces for single statement if blocks **should** be used.
* If some branch needs braces then all others should use them. Unless you have multiple `else if` in a row and the one needing the braces is only for a very small sub-block of code.
* Another exception would be when we have nested if blocks or generally multiple levels of code that affect code readability.
if (a < b) {
do(a);
}
else if (a > b) { // curly braces required here, then all branches should also add them
do(b);
do(d);
}
else {
do(c);
}
```
Generally it will depend on the particular piece of code and would be determined on how readable that piece of code is. **If in doubt** always use braces if one of the above exceptions applies.
#### g. Brace enclosed initializers ####
Unlike single-line functions, you must not insert spaces between the brackets and concluded expressions.<br/>
But you must insert a space between the variable name and initializer.
```c++
Class obj {}; // empty
Class obj {expr};
Class obj {expr1, /*...,*/ exprN};
QVariantMap map {{"key1", 5}, {"key2", 10}};
```
### 2. Indentation ###
### 3. Indentation ###
4 spaces.
### 3. File encoding and line endings ###
### 4. File encoding and line endings. ###
UTF-8 and Unix-like line ending (LF). Unless some platform specific files need other encodings/line endings.
### 4. Initialization lists ###
### 5. Initialization lists. ###
Initialization lists should be vertical. This will allow for more easily readable diffs. The initialization colon should be indented and in its own line along with first argument. The rest of the arguments should be indented too and have the comma prepended.
```c++
myClass::myClass(int a, int b, int c, int d)
@@ -207,7 +158,7 @@ myClass::myClass(int a, int b, int c, int d)
}
```
### 5. Enums ###
### 6. Enums. ###
Enums should be vertical. This will allow for more easily readable diffs. The members should be indented.
```c++
enum Days
@@ -222,7 +173,7 @@ enum Days
};
```
### 6. Names ###
### 7. Names. ###
All names should be camelCased.
#### a. Type names and namespaces ####
@@ -256,89 +207,40 @@ class MyClass
}
```
### 7. Header inclusion order ###
The headers should be placed in the following group order:
1. Module header (in .cpp)
2. C++ Standard Library headers
3. System headers
4. Boost library headers
5. Libtorrent headers
6. Qt headers
7. qBittorrent's own headers, starting from the *base* headers.
The headers should be ordered alphabetically within each group.
If there are conditionals for the same header group, then put them at the bottom of the respective group.
If there are conditionals that contain headers from several different header groups, then put them above the "qBittorrent's own headers" group.
One exception is the header containing the library version (for example, QtGlobal), this particular header isn't constrained by the aforementioned order.
### 8. Header inclusion order. ###
The headers should be placed in the following order:
1. Module header (in .cpp)
2. System/Qt/Boost etc. headers (splitted in subcategories if you have many).
3. Application headers, starting from *Base* headers.
The headers should be ordered alphabetically within each group (subgroup).<br/>
<br/>
Example:
```c++
// file: examplewidget.cpp
// examplewidget.cpp
// Module header
#include "examplewidget.h"
// exceptions, headers containing version number
#include <boost/version.hpp>
#include <libtorrent/version.hpp>
#include <QtGlobal>
// C++ Standard Library headers
#include <cmath>
#include <cstdio>
#ifdef Q_OS_WIN // conditional
#include <cmath>
#endif
// System headers
#ifdef Q_OS_WIN
#include <Windows.h>
#endif
// Boost library headers
#include <boost/circular_buffer.hpp>
// Libtorrent headers
#include <libtorrent/session.hpp>
// Qt headers
#include <QDateTime>
#include <QList>
#include <QString>
#include <QUrl>
#ifdef Q_OS_MAC // conditional
#include <QFont>
#endif
#include <libtorrent/version.hpp>
// conditional that contains headers from several different header groups
#if LIBTORRENT_VERSION_NUM >= 10100
#include <memory>
#include <QElapsedTimer>
#endif
// qBittorrent's own headers
#include "base/bittorrent/infohash.h"
#include "anothermodule.h"
#include "base/bittorrent/session.h"
#include "base/utils/fs.h"
#include "base/utils/misc.h"
#include "base/utils/string.h"
#include "ui_examplewidget.h"
```
### 8. Include guard ###
`#pragma once` should be used instead of "include guard" in new code:
```c++
// examplewidget.h
#pragma once
#include <QWidget>
class ExampleWidget : public QWidget
{
// (some code omitted)
};
```
### 9. Misc ###
### 9. Misc. ###
* Line breaks for long lines with operation:
@@ -414,16 +316,5 @@ i++, j--; // No
* Method definitions aren't allowed in header files
### 10. Git commit message ###
1. Limit the subject line to 50 characters. Subject should contain only the very essence of the changes (you should avoid extra details and internals)
2. Separate subject from body with a blank line
3. Capitalize the subject line
4. Do not end the subject line with a period
5. Use the imperative mood in the subject line (it's like you're ordering the program to do something (e.g. "Don't create temporary substrings")
6. Wrap the body at 72 characters
7. Use the body to explain what and why vs. how
8. If commit fixes a reported issue, mention it in the message body (e.g. `Closes #4134.`)
### 11. Not covered above ###
If something isn't covered above, just follow the same style the file you are editing has.
*This guide is not exhaustive and the style for a particular piece of code not specified here will be determined by project members on code review.*
### 10. Not covered above ###
If something isn't covered above, just follow the same style the file you are editing has. If that particular detail isn't present in the file you are editing, then use whatever the rest of the project uses.

View File

@@ -1,221 +1,35 @@
# How to contribute to qBittorrent
# Filing an issue
### Must read
* If you aren't sure, you can ask on the [**forum**](http://forum.qbittorrent.org) or read our [**wiki**](http://wiki.qbittorrent.org) first.
* Do a quick **search**. Others might already reported the issue.
* Write in **English**!
* Provide **version** information: (You can find version numbers at menu `Help -> About -> Libraries`)
```
qBittorrent:
Qt:
libtorrent:
boost:
OS version:
```
* Provide **steps** to reproduce the problem, it will be easier to pinpoint the fault.
* **Screenshots**! A screenshot is worth a thousand words. just upload it. [(How?)](https://help.github.com/articles/file-attachments-on-issues-and-pull-requests)
### Good to know
* **Be patient**. The dev team is small and resource limited. Devs finding their free time, analyzing the problem and fixing the issue, it all takes time. :clock3:
* If you can code, why not become a **contributor** by fixing the issue and open a pull request? :wink:
* Harsh words or threats won't help your situation. What's worse, your complain will (very likely) to be **ignored**. :fearful:
There are three main ways to contribute to the project.
Read the respective section to find out more.
### Table Of Contents
* **[Bug reporting etiquette](#bug-reporting-etiquette)**
* **[Submitting an issue/bug report](#submitting-an-issuebug-report)**
* [What is an actual bug report?](#what-is-an-actual-bug-report)
* [Before submitting a bug report](#before-submitting-a-bug-report)
* [Steps to ensure a good bug report](#steps-to-ensure-a-good-bug-report)
* **[Suggesting enhancements/feature requests](#suggesting-enhancementsfeature-requests)**
* [Before submitting an enhancement/feature request](#before-submitting-an-enhancementfeature-request)
* [Steps to ensure a good enhancement/feature suggestion](#steps-to-ensure-a-good-enhancementfeature-suggestion)
* **[Opening a pull request](#opening-a-pull-request)**
* [Must read](#must-read)
* [Good to know](#good-to-know)
# Bug reporting etiquette
* Issues, pull requests, and comments must always be in **English.**
* This project is supported by volunteers, do not expect "customer support"-style interaction.
* **Be patient.** The development team is small and resource limited. Developers and contributors take from their free time to analyze the problem and fix the issue. :clock3:
* Harsh words or threats won't help your situation. What's worse, your complain will (very likely) be **ignored.** :fearful:
# Submitting an issue/bug report
This section guides you through submitting an issue/bug report for qBittorrent.
Following these guidelines helps maintainers and the community understand your report, reproduce the behavior, and find related reports.
Make sure to follow these rules carefully when submitting a bug report. Failure to do so will result in the issue being closed.
## What is an actual bug report?
Developers and contributors are not supposed to deal with issues for which little to no investigation to find the actual cause of a purported issue was made by the reporter.
Positive contributions are those which are reported with efforts to find the actual cause of an issue, or at the very least efforts were made to narrow it as much as possible.
Requiring people to investigate as much as possible before opening an issue will more than likely avoid burdening the project with invalid issues or issues unrelated to qBittorrent.
The following are _not_ bug reports. **Check the [wiki][wiki-url], [forum][forum-url] or other places for help and support for issues like these**:
- Explanation of qBittorrent options (see [wiki][wiki-url]).
- Help with WebUI setup.
- Help with embedded tracker setup.
- Help about BitTorrent in general.
- Issues with specific search plugins.
- Asking for specific builds of qBittorrent other than the current one. You can install older releases at your own risk or for regression testing purposes. Previous Windows and macOS builds are available [here][builds-url].
- If you want older Linux builds, you will have to compile them yourself from the corresponding commits, or ask someone on the [forum][forum-url] to do it for you.
- Possibly others. Read on and use common sense.
The issue tracker is for provable issues only: You will have to make the case that the issue is really with qBittorrent and not something else on your side.
To make a case means to provide detailed steps so that anybody can reproduce the issue.
Be sure to rule out that the issue is not caused by something specific on your side.
Issue reports for bugs that apparently aren't easily reproducible or that you can't figure out what triggers it even though you tried are OK.
Any issue opened without effort to provide the required details for developers, contributors or anybody else to reproduce the problem will be closed as invalid.
For example:
- Crash reports with just a stack trace.
- Speculated performance issues that do not come with actual profiling data + analysis supporting the claim.
## Before submitting a bug report
- **Do some basic troubleshooting (examples)**:
- Restart qBittorrent.
- Restart your PC.
- Update your OS (e.g. Windows updates).
- Update your network card drivers.
- Fully reinstall qBittorrent.
- etc...
- Make sure the problem is not caused by anti-virus or other program messing with your files.
- Check if you can reproduce the problem in the latest version of qBittorrent.
- **Check [forum][forum-url] and [wiki][wiki-url].** You might be able to find the cause of the problem and fix things yourself.
- **Check if the issue exists already in the issue tracker.**
- If it does and the issue is still open, add a comment to the existing issue instead of opening a new one.
- If you find a Closed issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one.
- If the issue is with the search functionality:
- **Make sure you have [`python`][python-url] installed correctly (remember the search functionality requires a working python installation).**
- Make sure it is in fact a problem with the search functionality itself, and not a problem with the plugins. If something does not work properly with the search functionality, the first step is to rule out search plugin-related issues.
- For search plugin issues, report on the respective search plugin support page, or at [qbittorrent/search-plugins][search-plugins-url].
## Steps to ensure a good bug report
**Follow these guidelines** in order to provide as much useful information as possible right away. Not all of them are applicable to all issues, but you are expected to follow most of these steps (use common sense).
Otherwise, we've noticed that a lot of your time (and the developers') gets thrown away on exchanging back and forth to get this information.
* Use a **clear and descriptive title** for the issue to identify the problem.
* Post only **one specific issue per submission.**
* **Fill out the issue template properly.**
- **Make sure you are using qBittorrent on a supported platform.** Do not submit issues which can only be reproduced on beta/unsupported releases of supported operating systems (e.g. Windows 10 Insider, Ubuntu 12.04 LTS, etc).
These are unstable/unsupported platforms, and in all likelihood, whatever the issue is, it is not related to qBittorrent.
* **Specify the OS you're using, its version and architecture.**
* Examples: Windows 8.1 32-bit, Linux Mint 17.1 64-bit, Windows 10 Fall creators Update 64-bit, etc.
* **Report only if you run into the issue with an official stable release, a beta release, or with the most recent upstream changes (in this last case specify the specific commit you are on).** (beta testing is encouraged :smile:). We do not provide support for bugs on unofficial Windows builds.
* **Specify the version of qBittorrent** you are using, as well as its **architecture** (x86 or x64) and its **libraries' versions** (Help -> About -> Libraries).
* Specify **how you installed**:
- Linux: either from the PPA, your distribution's repositories, or compiled from source, or even possibly third-party repositories.
- Windows: either from the installer, or compiled from source, or even possibly third-party repositories.
- macOS: either from the installer, or compiled from source, or even possibly third-party repositories.
* **Describe the exact steps which reproduce the problem in as many details as possible.**
- For example, start by explaining how you started qBittorrent, e.g. was it via the terminal? Desktop icon? Did you start it as root or normal user?
- **When listing steps, don't just say what you did, but explain how you did it.**
- For example, if you added a torrent for download, did you do so via a `.torrent` file or via a magnet link? If it was with a torrent file did you do so by dragging the torrent file from the file manager to the transfer list, or did you use the "Add Torrent File" in the Top Bar?
- Describe the behavior you observed after following the steps and point out what exactly is the problem with that behavior; this is what we'll be looking for after executing the steps.
* **Explain which behavior you expected to see instead** and why.
* Use **screenshots/animated GIFs to help describe the issue** whenever appropriate [(How?)][attachments-howto-url].
* If the problem wasn't triggered by a specific action, describe what you were doing before the problem happened.
* **If you are reporting that qBittorrent crashes**, include the stack trace in the report; include it in a code block, a file attachment, or put it in a gist and provide link to that gist.
* **For performance-related issues**, include as much profiling data as you can (resource usage graphs, etc).
* Paste the **qBittorrent log** (or put the contents of the log in a gist and provide a link to the gist). The log can be viewed in the GUI (View -> Log -> tick all boxes). If you can't do that, the file is at:
- Linux: `~/.local/share/data/qBittorrent/logs/qBittorrent.log`
- Windows: `%LocalAppData%\qBittorrent\logs`
- macOS: `~/Library/Application Support/qBittorrent/qBittorrent.log`
* **Do NOT post comments like "+1" or "me too!"** without providing new relevant info on the issue. Using the built-in reactions is OK though. Remember that you can use the "subscribe" button to receive notifications of that report without having to comment first.
* If there seems to be an **issue with specific torrent files/magnet links**:
- Don't post private `.torrent` files/magnet links, or ones that point to copyrighted content. If you are willing, offer to email a link or the `.torrent` file itself to whoever developer is debugging it and requests it.
- Make sure you can't reproduce the problem with another client, to rule out the possibility that the issue is with the `.torrent` file/magnet link itself.
* A screenshot, transcription or file upload of any of **qBittorrent's preferences that differ from the defaults.** Please include everything different from the defaults whether or not it seems relevant to your issue.
* **Attachment rules**:
- Short logs and error messages can be pasted as quotes/code whenever small enough; otherwise make a gist with the contents and post the link to the gist.
- Avoid linking/attaching impractical file formats such as PDFs/Word documents with images. If you want to post an image, just post the image.
### Provide more context by answering these questions (if applicable):
- Can you **reliably reproduce the issue?** If not, provide details about how often the problem happens and under which conditions it normally happens (e.g. only happens with extremely large torrents/only happens after qBittorrent is open for more than 2 days/etc...)
- Did the problem start happening recently (e.g. after updating to a new version of qBittorrent) or was this always a problem?
- If the problem started happening recently, can you reproduce the problem in an older version of qBittorrent?
- Are you saving files locally (in a disk in your machine), or are you saving them remotely (e.g. network drives)?
- Are you using qBittorrent with multiple monitors? If so, can you reproduce the problem when you use a single monitor?
Good read: [How to Report Bugs Effectively][howto-report-bugs-url]
# Suggesting enhancements/feature requests
This section guides you through submitting an enhancement suggestion for qBittorrent, including completely new features and minor improvements to existing functionality.
Following these guidelines helps maintainers and the community understand your suggestion and find related suggestions.
## Before submitting an enhancement/feature request
* Check the [wiki][wiki-url] and [forum][forum-url] for tips — you might discover that the enhancement is already available.
* Most importantly, check if you're using the latest version of qBittorrent and if you can get the desired behavior by changing qBittorrent's settings.
* Check in the [releases][releases-url] page or on the [forum][forum-url], see if there's already a alpha/beta version with that enhancement.
* Perform a cursory search to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
## Steps to ensure a good enhancement/feature suggestion
- Specify which version of qBittorrent you're using.
- Specify the name and version of the OS you're using.
- Provide a step-by-step description of the suggested enhancement in as many details as possible.
- Describe the current behavior and explain which behavior you expected to see instead and why.
- Include screenshots and animated GIFs which help you demonstrate the steps or point out the part of qBittorrent which the suggestion is related to.
- If this enhancement exists in other BitTorrent clients, list those clients.
# Opening a pull request
### Must read
* Read our [**coding guidelines**][coding-guidelines-url]. There are some scripts to help you: [uncrustify script][uncrustify-script-url], [astyle script][astyle-script-url], [(related thread)][coding-guidelines-thread-url].
* Keep the title **short** and provide a **clear** description about what your pull request does.
* Provide **screenshots** for UI related changes.
* Keep your git commit history **clean** and **precise.** Refer to the section about "Git commit messages" in the [**coding guidelines**][coding-guidelines-url].
* If your commit fixes a reported issue (for example #4134), add the following message to the commit `Closes #4134.`. Example [here][commit-message-fix-issue-example-url].
* Read our [**coding guidelines**](https://github.com/qbittorrent/qBittorrent/blob/master/CODING_GUIDELINES.md). There are some scripts to help you: [uncrustify script](https://raw.githubusercontent.com/qbittorrent/qBittorrent/master/uncrustify.cfg), [astyle script](https://gist.github.com/Chocobo1/539cee860d1eef0acfa6), [(related thread)](https://github.com/qbittorrent/qBittorrent/issues/2192).
* Keep the title **short** and provide a **clear** description about what your pull request does.
* Provide **screenshots** for UI related changes.
* Keep your git commit history **clean** and **precise**. Commits like `xxx fixup` should not appear.
* If your commit fix a reported issue (for example #4134), add the following message to the commit `Closes #4134.`. Example [here](https://github.com/qbittorrent/qBittorrent/commit/a74bac20c4e8de9776bf9bb77fdc7526135d1988).
### Good to know
* **Search** pull request history! Others might have already implemented your idea and it is waiting to be merged (or got rejected already). Save your precious time by doing a search first.
* When resolving merge conflicts, do `git rebase <target_branch_name>`, don't do `git pull`. Then you can start fixing the conflicts. Here is a good explanation: [link][merging-vs-rebasing-url].
[astyle-script-url]: https://gist.github.com/Chocobo1/539cee860d1eef0acfa6
[attachments-howto-url]: https://help.github.com/articles/file-attachments-on-issues-and-pull-requests
[coding-guidelines-url]: https://github.com/qbittorrent/qBittorrent/blob/master/CODING_GUIDELINES.md
[coding-guidelines-thread-url]: https://github.com/qbittorrent/qBittorrent/issues/2192
[commit-message-fix-issue-example-url]: https://github.com/qbittorrent/qBittorrent/commit/c07cd440cd46345297debb47cb260f8688975f50
[forum-url]: http://forum.qbittorrent.org/
[howto-report-bugs-url]: https://www.chiark.greenend.org.uk/~sgtatham/bugs.html
[merging-vs-rebasing-url]: https://www.atlassian.com/git/tutorials/merging-vs-rebasing
[python-url]: https://www.python.org/
[releases-url]: https://github.com/qbittorrent/qBittorrent/releases
[search-plugins-url]: https://github.com/qbittorrent/search-plugins
[uncrustify-script-url]: https://raw.githubusercontent.com/qbittorrent/qBittorrent/master/uncrustify.cfg
[wiki-url]: https://github.com/qbittorrent/qBittorrent/wiki
[builds-url]: https://sourceforge.net/projects/qbittorrent/files/
* **Search** pull request history! Others might already implemented your idea and is waiting to be merged (or got rejected already). Save your precious time by doing a search first.
* When resolving merge conflicts, do `git rebase <target_branch_name>`, don't do `git pull`. Then you can start fixing the conflicts. Here is a good explanation: [link](https://www.atlassian.com/git/tutorials/merging-vs-rebasing).

418
Changelog
View File

@@ -1,379 +1,3 @@
* Thu Oct 31 2019 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.1.9.1
- WINDOWS: Fix a problem with bigger dialogs due to wrong DPI reported by the system (Chocobo1)
* Sun Oct 27 2019 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.1.9
- BUGFIX: Preserve relative order when moving to top/bottom in queue (Chocobo1)
- WINDOWS: Use real physical screen DPI (Chocobo1)
- WEBUI: Bump Web API version
* Mon Sep 23 2019 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.1.8
- BUGFIX: Fix filename validation on non-Windows OS (Chocobo1)
- BUGFIX: ScanFolders/FileSystemWatcher now detect magnet files with case insensitivity in filename (Chocobo1)
- BUGFIX: Fix failed seeding after creating a torrent and auto-adding it to the session (Chocobo1)
* Sun Aug 04 2019 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.1.7
- FEATURE: Add 12 hour and 24 hour speed graphs (dzmat)
- FEATURE: Change "Add new torrent" dialog to horizontal layout (Evgeny Lensky)
- BUGFIX: Fix messed up symbols in log (Chocobo1)
- BUGFIX: Fix incomplete file extension not applied for new torrents (Chocobo1)
- BUGFIX: Save updated resume data for completed torrents (Vladimir Golovnev (Glassez))
- BUGFIX: Fix requested torrent resume data handling (Vladimir Golovnev (Glassez))
- BUGFIX: Prevent command injection via "Run external program" function (Chocobo1)
- BUGFIX: Avoid race conditions when adding torrent (Vladimir Golovnev (Glassez))
- BUGFIX: Fix torrent checking issues (Vladimir Golovnev (Glassez))
- BUGFIX: Use proper log message when there are no error (Chocobo1)
- BUGFIX: Fix torrent properties not saved for paused torrents (Chocobo1)
- BUGFIX: Some improvements on qtsingleapplication code (Chocobo1)
- BUGFIX: Remove limits of "Disk cache expiry interval" setting (Chocobo1)
- BUGFIX: Remove upper limit of "Disk cache" setting (Chocobo1)
- BUGFIX: Fix crash when removing phantom tags (Chocobo1)
- BUGFIX: Improve handleFileErrorAlert error message (Chocobo1)
- BUGFIX: Fix updated save path not saved for paused torrents (Chocobo1)
- BUGFIX: Log save_resume_data_failed_alert (Chocobo1)
- BUGFIX: Don't remove parent directories (Chocobo1)
- BUGFIX: Properly remove empty leftover folders after rename (Chocobo1)
- BUGFIX: Focus behavior row in Options dialog (silverqx)
- BUGFIX: Fix unable to rename folder on Windows when same is used in different case(Chocobo1)
- BUGFIX: Fix unable to control add torrent dialogs when opened simultaneously (Chocobo1)
- BUGFIX: Disable "Upload mode" when start preloaded torrent (Vladimir Golovnev (Glassez))
- BUGFIX: Fix wrong comparison result when sorting items(Chocobo1)
- BUGFIX: Fix sequential downloading when redirected (Vladimir Golovnev (Glassez))
- BUGFIX: Fix typos (Chocobo1)
- BUGFIX: Fix assertion fail (Chocobo1)
- BUGFIX: Change number of time axis divisions from 5 to 6 for convenience (dzmat)
- BUGFIX: Don't turn window blank when closed to system tray (Ekin Dursun)
- WEBUI: Fix WebUI encoding of special characters (Thomas Piccirello)
- WEBUI: Change the speed unit from Bytes/s to KiB/s for the rate limiter(jerrymakesjelly)
- WEBUI: Fix '+' char not decoded to space correctly (Chocobo1)
- RSS: Ignore RSS articles with non-unique identifiers (Vladimir Golovnev (Glassez))
- RSS: Perform more RSS parsing in working thread (Vladimir Golovnev (Glassez))
- RSS: Download RSS enclosure element if no proper MIME type is found (Matan Bareket)
* Sun May 05 2019 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.1.6
- BUGFIX: Force recheck multiple torrents one by one in all possible cases. Closes #9120 (glassez)
- BUGFIX: Don't query Google for tracker favicons, for privacy reasons (sledgehammer999)
- BUGFIX: Work around the crash occurred in QTimer. Closes #9985 (Chocobo1)
- BUGFIX: Increase the .torrent file download size limit to 100 MiB (thalieht)
- BUGFIX: Disable downloading tracker favicons by default. Works around reported crashes in Linux. Closes #9667 (Chocobo1)
- WEBUI: Separate URL components before percent-decoding. Allow special characters in query string parameters. Closes #9116 (glassez)
- WEBUI: Prevent login credential appearing in URL. Closes #10221 (Chocobo1)
- WEBUI: Display warning when Javascript is disabled (Chocobo1)
- WEBUI: Fix translatable strings (Chocobo1)
- WEBUI: Correctly handle '+' sign in x-www-form-urlencoded data. Closes #10451 (Chocobo1)
- WEBUI: Remove closed connections immediately. Closes #10487 (Chocobo1)
- WEBUI: Fix "Create subfolder" option is not working. Closes ##10392 (Chocobo1)
- SEARCH: Make num enter key work the same as return in searchjobwidget (thalieht)
- LINUX: Make window title bar icon work in Wayland (Peter Eszlari)
- LINUX: Update appdata.xml file (Chocobo1)
- MACOS: Fix progress bar drawing by using different style than native (Nick Korotysh)
- MACOS: Updated and cleaned up fields in Info.plist (Nick Korotysh)
- OTHER: Mention more translators in the about tab. Closes #10043 (sledgehammer999)
* Mon Dec 24 2018 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.1.5
- FEATURE: Add checking_mem_usage option to AdvancedSettings (FranciscoPombal)
- FEATURE: Save torrents queue in separate file. Now a new file named 'queue' is created, saving on each line the infohash of each queued torrent in sorted order. (glassez)
- BUGFIX: Fix regression on resuming torrents without metadata (thalieht)
- BUGFIX: Reorder and rename Tracker list context menu option (Thomas Piccirello)
- BUGFIX: Rename Tracker List columns (Thomas Piccirello)
- BUGFIX: Show error message when Session failed to start (glassez)
- BUGFIX: Embedded tracker: Use ip parameter from tracker request if provided (Chocobo1)
- BUGFIX: Fix weekday names translations (Chocobo1)
- BUGFIX: Fix strings not translated (Chocobo1)
- WEBUI: Change qBittorrent exit message to HTML5 (Chocobo1)
- WEBUI: Revise CSP header (Chocobo1)
- WEBUI: Enforce referrer-policy in WebUI (Chocobo1)
- WEBUI: Add torrent name filtering to WebUI (Thomas Piccirello)
- WEBUI: Send numeric status without translation (Thomas Piccirello)
- WEBUI: Add WebUI Trackers context menu (Thomas Piccirello)
- WEBUI: Add DHT, PeX, and LSD to WebUI Tracker list (Thomas Piccirello)
- WEBUI: Add additional Tracker columns to WebUI (Thomas Piccirello)
- WEBUI: Bump Web API version
- WEBUI: Fix display bugs in WebUI Files tab. Remove <IE9 support (Thomas Piccirello)
- WEBUI: Fix incorrect priority value sent from WebUI (Thomas Piccirello)
- WEBUI: Set priority for multiple files in one WebAPI request (Thomas Piccirello)
- WEBUI: Match WebUI Peers table column order to GUI (Thomas Piccirello)
- WEBUI: Fetch data less frequently when torrents tab isn't visible (Thomas Piccirello)
- WEBUI: Add Search tab to WebUI (Thomas Piccirello)
- WEBUI: Add ability to pass urls to the webui download page (Thomas Piccirello)
- WEBUI: Fix JavaScript error (Tom Piccirello)
- WEBUI: Disallow setting a blank alternative WebUI location (Thomas Piccirello)
- WEBUI: Add slow torrent options (Thomas Piccirello)
- WEBUI: Add "Use alternative Web UI" option (Thomas Piccirello)
- WEBUI: Add "Apply rate limit to peers on LAN" option (Thomas Piccirello)
- WEBUI: Add email "From" option (Thomas Piccirello)
- WEBUI: Set WebUI download options using set preferences (Thomas Piccirello)
- WEBUI: Show list of categories on WebUI download page (Thomas Piccirello)
- WEBUI: Hide WebUI text input for custom monitor save locations (Thomas Piccirello)
- WEBUI: Add "When adding a torrent" options (Thomas Piccirello)
- WEBUI: Add WebUI Auto TMM options (Thomas Piccirello)
- WEBUI: Add speed limit icons to WebUI Speed options (Thomas Piccirello)
- WEBUI: Add WebUI Random port button and proxy unencrypted password notice (Thomas Piccirello)
- WEBUI: Replace WebUI Options fixed-width labels (Thomas Piccirello)
- WEBUI: Reorder WebUI options to match GUI (Thomas Piccirello)
- WEBUI: Allow WebUI sidebar to be collapsed (Thomas Piccirello)
- WEBUI: Show ellipsis when WebUI sidebar is too narrow (Thomas Piccirello)
- WEBUI: Fix WebUI bug on override of Start Download option.Closes #9855. (Tom Piccirello)
- WEBUI: Fix missing words in WebUI (Chocobo1)
- WEBUI: Add SameSite attribute to WebUI session cookie (Thomas Piccirello)
- WEBUI: Put WebUI security related options into a groupbox (Chocobo1)
- WEBUI: Add option for WebUI Host header validation (Chocobo1)
- WEBUI: Show icon in WebUI sorted column (Thomas Piccirello)
- RSS: Keep track of REPACK/PROPER downloads. Closes #9898. (Stephen Dawkins)
- SEARCH: Only instantiate SearchPluginManager as needed (Thomas Piccirello)
- MACOS: Make file icon look like other macOS icons (Nick Korotysh)
- MACOS: Save option to start minimized in Mac (thalieht)
* Mon Nov 19 2018 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.1.4
- FEATURE: Recognize *.ts files as previewable (silver)
- FEATURE: Allow to disable speed graphs (dzmat)
- FEATURE: Clear LineEdit on ESC (silverqx)
- BUGFIX: Fix divide-by-zero crash (Chocobo1)
- BUGFIX: Remove speed limit checkbox in Options dialog (Chocobo1)
- BUGFIX: Fix speed graph "high speeds" bug (dzmat)
- BUGFIX: Don't update torrent status unnecessarily (glassez)
- BUGFIX: Improve force recheck of paused torrent (glassez)
- BUGFIX: Restore torrent in two steps (glassez)
- BUGFIX: Improve scaling of speed graphs (dzmat)
- BUGFIX: Add isNetworkFileSystem() detection on Windows. This allows network mounts to be monitored correctly by polling timer. (Chocobo1)
- BUGFIX: Reduce horizontal graphs resolution. Improves perfomance. (dzmat)
- BUGFIX: Don't recheck just checked torrent (mj-p, glassez)
- BUGFIX: Add SMB2 magic number (Chocobo1)
- BUGFIX: Restore startup perfomance to v4.1.2 times. Needs at least libtorrent 1.1.10 (sledgehammer999)
- BUGFIX: Make strings actually translatable (sledgehammer999)
- WEBUI: Handle downloading .torrent file as success (Tom Piccirello)
- WEBUI: Fix Alternative Web UI to be available (glassez)
- WEBUI: Consider empty locale setting as not set (glassez)
- WEBUI: Add free disk space to WebUI status bar (Thomas Piccirello)
- WEBUI: Add WebUI search API controller (Thomas Piccirello)
- WEBUI: Fix WebUI Auto TMM context menu bug (Thomas Piccirello)
- WEBUI: Use independent translation for WebUI (glassez)
- WEBUI: Add categories WebAPI (Thomas Piccirello)
- WEBUI: Fix minor JavaScript defects (Thomas Piccirello)
- WEBUI: Add locale to js file path (Thomas Piccirello)
- WEBUI: Translate WebUI torrents Status column (Thomas Piccirello)
- WEBUI: Bump Web API version
- RSS: Allow to disable downloading REPACK/PROPER matches (Stephen Dawkins)
- RSS: Improve RSS Feed updating (glassez)
- SEARCH: Allow resizing search filter in search job (thalieht)
- SEARCH: Improve parser for search engine versions.txt (Chocobo1)
- SEARCH: Update Python URLs (Chocobo1)
- SEARCH: Fix asking to install Python (Chocobo1)
- SEARCH: Reformat python code to be compliant with PEP8 (Chocobo1)
- OTHER: cmake: restore out-of-source build (Eugene Shalygin)
- OTHER: cmake: cmake: use C++14 when available (Eugene Shalygin)
* Tue Sep 18 2018 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.1.3
- FEATURE: Preselect name without extension when renaming files (thalieht)
- FEATURE: Allow setting seq & first/last from context menu without metadata (thalieht)
- BUGFIX: Show "N/A" if there is no scrape (thalieht)
- BUGFIX: Save option about tracker favicons under correct key (sledgehammer999)
- BUGFIX: When file data are unreachable pause torrent and show "Missing Files" status (temporary fix) (sledgehammer999)
- BUGFIX: Don't disable DHT when using force proxy (Thomas Piccirello)
- BUGFIX: Correctly save torrent queue position/state/priority changes in fastresume (glassez, thalieht, sledgehammer999)
- BUGFIX: Fix icon height/width ratio (Chocobo1)
- BUGFIX: Fix values sorted wrong in "Last Activity" column (Chocobo1)
- BUGFIX: Replace png icons with svg (Chocobo1)
- WEBUI: Allow WebUI sidebar filters to be hidden (Thomas Piccirello)
- WEBUI: Increase WebUI Options initial height (Thomas Piccirello)
- WEBUI: Adjust WebUI Options form alignment (Thomas Piccirello)
- WEBUI: Fix WebUI unreachable issue (Chocobo1)
- WEBUI: Require torrent category creation to be explicit (Thomas Piccirello)
- WEBUI: Include category save path in web api sync data (Thomas Piccirello)
- WEBUI: Add save path and editing to WebUI new category dialog (Thomas Piccirello)
- WEBUI: Bump Web API version
- SEARCH: Refactor in searchjob to always color visited entries (thalieht)
- SEARCH: Set "enter" as shortcut to download the selected torrents in search job (thalieht)
- SEARCH: Add regex option in the search filter's context menu (thalieht)
- LINUX: Fix GUI scaling issue on Linux (Chocobo1)
- LINUX: Fix regression that broke installing desktop file (Eli Schwartz)
- OPENBSD: Better filesystem support for filewatcher (Elias M. Mariani)
* Sun Aug 12 2018 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.1.2
- FEATURE: New options for "inhibit sleep" (Lukas Greib)
- FEATURE: Add option for regexps in the transferlist search filter's context menu (thalieht)
- FEATURE: Add async io threads option to AdvancedSettings (tjjh89017)
- FEATURE: Allow save resume interval to be disabled (Chocobo1)
- FEATURE: Add checkbox for recursive download dialog (Chocobo1)
- FEATURE: Add changelog link in program updater (Chocobo1)
- BUGFIX: Avoid allocating large memory when loading a .torrent file (Couchy)
- BUGFIX: Notify users on 1st time close/minimize to tray (sledgehammer999)
- BUGFIX: Fix I/O error after fetching magnet metadata (Chocobo1)
- BUGFIX: Never save resume data for already paused torrents (glassez)
- BUGFIX: Make ProgramUpdater upgrade to 64-bit qbt when running on 64-bit Windows (Chocobo1)
- BUGFIX: Put temporary files in qbt own temp folder (Chocobo1)
- BUGFIX: Avoid potentially setting the wrong piece priorities (Chocobo1)
- BUGFIX: Various code refactorings/improvements (Chocobo1, thalieht, glassez)
- BUGFIX: Add options "Download in sequential order" and "Download first and last pieces first" in AddNewTorrentDialog (Chocobo1)
- BUGFIX: Download favicon using appropriate protocol (glassez)
- BUGFIX: Apply proxy settings on DownloadManager creation (glassez)
- BUGFIX: Improve torrent initialization (glassez)
- BUGFIX: Save resume data on torrent change events (glassez)
- BUGFIX: Increase default resume data save interval (Chocobo1)
- BUGFIX: Work around crash when procesing recursive download. Closes #9086 (Chocobo1)
- BUGFIX: Reduce queries to python version (Chocobo1)
- BUGFIX: Disable certain mouse wheel events in Options dialog (Chocobo1)
- WEBUI: Send all rechecks in one request (Thomas Piccirello)
- WEBUI: Add WebUI Force Reannounce option (Thomas Piccirello)
- WEBUI: Create non-existing path in setLocationAction() (Goshik)
- WEBUI: Add WebUI support for Mac ⌘ (Command) key (Thomas Piccirello)
- WEBUI: Show current save path in 'Set location' window (Goshik)
- WEBUI: Fix WebUI cache behavior for css files (Chocobo1)
- WEBUI: Send Cache-Control header in WebUI responses (Chocobo1)
- WEBUI: Add form-action to CSP (Thomas Piccirello)
- WEBUI: Add upgrade-insecure-requests to CSP when HTTPS is enabled (Thomas Piccirello)
- WEBUI: Reset WebUI ban counter on login success (Chocobo1)
- WEBUI: Add logging messages in WebUI login action (Chocobo1)
- WEBUI: Add option to control CSRF protection (Chocobo1)
- WEBUI: Add option to control WebUI clickjacking protection (Chocobo1)
- RSS: Implement "Sequential downloading" feature. Closes #6835 (glassez)
- RSS: Don't use RSS feed URLs as base for file names. Closes #8399 (glassez)
- SEARCH: Add a name filter for search results (thalieht)
- SEARCH: Fix python version detection (Chocobo1)
- SEARCH: Clear python cache conditionally (Chocobo1)
- SEARCH: Properly normalize version string before parsing it (hannsen)
- WINDOWS: Turn on Control Flow Guard for MSVC builds (Chocobo1)
- MACOS: Replace deprecated function IOPMAssertionCreate() on macOS (Chocobo1)
- OTHER: Fix CMake build with QtSingleApplication. Fixes #9196 (Eugene Shalygin)
* Sun May 27 2018 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.1.1
- FEATURE: Add 'Moving' state for torrents being relocated/moved (sledgehammer999)
- FEATURE: Show rechecking progress (sledgehammer999)
- FEATURE: Add option to remember last used save path (glassez)
- FEATURE: Torrent name is also renamed if the content was renamed in the "Add New Torrent" dialog (glassez)
- FEATURE: Relax behavior of "Download first and last piece first". It applies to all files and not only to the previewable. (Chocobo1)
- BUGFIX: Fix issues with translatable strings (Chocobo1)
- BUGFIX: Fix displayed tracker messages (Chocobo1)
- BUGFIX: Make settings file recovery more robust (Chocobo1)
- BUGFIX: Retry saving settings when operation failed (Chocobo1)
- BUGFIX: Log successful torrent move (sledgehammer999)
- BUGFIX: Fix deletion of old logs (sledgehammer999)
- BUGFIX: Delete non-commited fastresume files (sledgehammer999)
- BUGFIX: Don't migrate torrents that have newer fastresumes (sledgehammer999)
- BUGFIX: Fix adding multiple torrents at once from WebUI (glassez)
- BUGFIX: Improve "Run External Program" behavior. On Windows, a backslash isn't appended to paths from path variables (Chocobo1)
- BUGFIX: Suppress multiple I/O errors for the same torrent (sledgehammer999)
- BUGFIX: Replace raster qbt logo with vector version (Chocobo1)
- WEBUI: Fix wrong API method names (glassez)
- WEBUI: Filter torrent info endpoint by hashes (Marcel Petersen)
- WEBUI: Fix invalid API calls in WebUI (glassez)
- WEBUI: Improve legacy API params handling (glassez)
- WEBUI: Fix params handling for some legacy API methods (glassez)
- WEBUI: Apply locale changes immediately in WebUI (Chocobo1)
- WEBUI: Use 32px icons for favicon (Chocobo1)
- WEBUI/RSS: Properly set RSS settings via API (glassez)
- RSS: Fix auto-downloading rule when Smart filter with regular Episode filter are used (glassez)
- RSS: Make "Ignoring days" to behave like other filters (glassez)
- RSS: Place "Use Smart Episode Filter" more correctly (glassez)
- RSS: Use RSS feed update time as a fallback (glassez)
- COSMETIC: Fix Stats dialog size (sledgehammer999)
- MACOS: Fix GUI scaling factor on macOS (Chocobo1)
- WINDOWS: Update icons (adem4ik)
- LINUX: Fix open destination folder with Nautilus > 3.28 (Evgeny Lensky)
- OTHER: Code improvements and refactoring (thalieht, Nick Korotysh, Chocobo1)
* Sat May 05 2018 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.1.0
- FEATURE: Add "Coalesce reads & writes" checkbox in advanced options (Chocobo1)
- FEATURE: Smart Filter for RSS (Stephen Dawkins)
- FEATURE: Possibility to configure at which speed a torrent is considered slow (thalieht)
- FEATURE: When creating a torrent you can choose to preserve the file order (toster, Chocobo1)
- FEATURE: A new, redesigned and refactored WebAPI (glassez)
- BUGFIX: Redefine CacheStatus.readRatio field. (Chocobo1)
- BUGFIX: Clarify some terms in stats dialog (Chocobo1)
- BUGFIX: Fix possible crash when using both share limits (thalieht)
- BUGFIX: Disable options when `Disable connections not supported by proxies` is enabled (Thomas Piccirello)
- BUGFIX: Add link to an explanation of `Disable connections not supported by proxies` (Thomas Piccirello)
- BUGFIX: Fix typo in a log message (Andrei Stepanov)
- BUGFIX: Fix loading very large torrents. Closes #8449. (Chocobo1)
- BUGFIX: Fix reverting backslashes to slashes in run external program. Closes #7800 (Chocobo1)
- BUGFIX: Use https for documentation links (Chocobo1)
- BUGFIX: Use original scheme when downloading favicons (Chocobo1)
- BUGFIX: Parse URL query string at application level (glassez)
- BUGFIX: Properly reply to announce request (embedded tracker) (glassez)
- BUGFIX: Add `Tags` parameter to "Run External Program" (Chocobo1)
- BUGFIX: Fix various typos (Chocobo1)
- BUGFIX: Refactor filesystem watcher. Delay before processing new files. (Chocobo1)
- BUGFIX: Don't strip empty arguments passed to external program. Closes #8454. (Chocobo1)
- BUGFIX: Stop creating Download folder on start (Chocobo1)
- BUGFIX: Avoid data corruption when rechecking paused torrents (sledgehammer999)
- BUGFIX: Fix crashes due to invalid iterator use (Luís Pereira)
- BUGFIX: Fix renaming completed files (Chocobo1)
- BUGFIX: Fix path separator in log messages (Chocobo1)
- WEBUI: Switch built-in Web UI html to HTML5 (glassez)
- WEBUI: WebUI Save user's resized window sizes (Thomas Piccirello)
- WEBUI: Make download + upload windows resizable (Thomas Piccirello)
- WEBUI: Add option to show/hide webui status bar (Thomas Piccirello)
- WEBUI: Add "Use proxy only for torrents" option to webui (Thomas Piccirello)
- WEBUI: Various fixes in the html code (Thomas Piccirello)
- WEBUI: Don't unselect selected torrents after a few seconds (Thomas Piccirello)
- WEBUI: Enable Http/1.1 persistence connection (Chocobo1)
- WEBUI: Format Read cache hits as percentage (Thomas Piccirello)
- WEBUI: Re-order and rename stats (Thomas Piccirello)
- WEBUI: Right align stat values (Thomas Piccirello)
- WEBUI: Enable Statistics window to be scrolled and resized (Tom Piccirello)
- WEBUI: Save WebUI Statistics window size (Thomas Piccirello)
- WEBUI: Make WebUI iframe windows scrollable on iOS (Thomas Piccirello)
- WEBUI: Remove unused CSS from WebUI login page (Thomas Piccirello)
- WEBUI: Consolidate CSS into style.css (Thomas Piccirello)
- WEBUI: Resolve JavaScript errors (Thomas Piccirello)
- WEBUI: Fix spacing in login form(Thomas Piccirello)
- WEBUI: Update WebUI to be more compliant with HTML5 standard (Chocobo1)
- WEBUI: Update clipboard.js to v2.0.0 (Chocobo1)
- WEBUI: Remove unused JavaScript library (Chocobo1)
- WEBUI: Fix setting preferences via WebAPI (glassez)
- WEBUI: Rename property to match its definition (Thomas Piccirello)
- WEBUI: Add Limit Share Ratio context menu option (Thomas Piccirello)
- RSS: Disable Auto TMM when RSS rule has save path (glassez)
- RSS: Process loaded RSS articles in case of error (glassez)
- RSS: Resolve (X)HTML entities in RSS content (glassez)
- SEARCH: Improve Search handling (glassez)
- SEARCH: Calculate supported categories based on selected plugin (Thomas Piccirello)
- SEARCH: Fix memory leak (Chocobo1)
- COSMETIC: Use spinbox suffix to display rate/time units (thalieht)
- COSMETIC: Avoid showing an empty row in AdvancedSettings (Chocobo1)
- OTHER: Various code optimizations and fixes (Luís Pereira, Chocobo1)
- OTHER: Fix build when using Clang under CMake (Luís Pereira)
- OTHER: Allow to disable Stacktrace support (Nick Korotysh)
- OTHER: Use RNG provided by OS (Chocobo1)
* Fri Feb 16 2018 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.0.4
- FEATURE: Add source field in Torrent creator. Closes #7965. (Chocobo1)
- FEATURE: Torrent creator: raise maximum piece size to 32 MiB (Chocobo1)
- FEATURE: Add a force reannounce option in the transfer list context menu. Closes #6448. (Jesse Bryan)
- BUGFIX: Fix sorting of country flags column in Peers tab. (sledgehammer999)
- BUGFIX: Fix natural sorting when the common part of 2 strings ends partially in a number which continues in the uncommon part. Closes #8080 #6732. (sledgehammer999)
- BUGFIX: Fix application of speed limits on LAN and μTP connections. Closes #7745. (sledgehammer999)
- BUGFIX: Make peer information flags in peerlist more readable. (thalieht)
- BUGFIX: Fix gui issues on high DPI monitor. (Chocobo1)
- BUGFIX: Fix dialog and column size on high DPI monitors. (Chocobo1)
- BUGFIX: Fix constant status of '[F] Downloading'. Closes #7628. (sledgehammer999)
- BUGFIX: Fix translation context. Closes #8211. (sledgehammer999)
- BUGFIX: Separate subnet whitelist options into two lines. (Thomas Piccirello)
- BUGFIX: Don't set application name twice. (Luís Pereira)
- BUGFIX: Set default file log size to 65 KiB and delete backup logs older than 1 month. (sledgehammer999)
- WEBUI: Only prepend scheme when it is not present. Closes #8057. (Chocobo1)
- WEBUI: Add "Remaining" and "Availability" columns to webui Content tab. (Thomas Piccirello)
- WEBUI: Make value formatting consistent with GUI (Thomas Piccirello)
- WEBUI: Reposition Total Size column to match gui (Thomas Piccirello)
- WEBUI: Add Tags and Time Active columns (Thomas Piccirello)
- WEBUI: Use https for www.qbittorrent.org (Thomas Piccirello)
- WEBUI: Match webui statuses to gui, closes #7516 (Thomas Piccirello)
- WEBUI: Right-align stat values (Thomas Piccirello)
- WEBUI: Add missing units. (Thomas Piccirello)
- RSS: Fix crash when deleting rule because it tries to update. Closes #8094 (glassez)
- RSS: Don't process new/updated RSS rules when disabled (glassez)
- RSS: Remove legacy and corrupted RSS settings (glassez)
- SEARCH: Search only when category is supported by plugin. Closes #8053. (jan.karberg)
- SEARCH: Only add search separators as needed. (Thomas Piccirello)
- COSMETIC: Tweak spacing in torrent properties widget and speed widget. (Chocobo1)
- WINDOWS: Use standard folder icon for open file behavior on Windows. Closes #7880. (Chocobo1)
- WINDOWS: Revert "Run external program" function. Now you will not be able to directly run batch scripts. (Chocobo1)
- MACOS: Fix torrent file selection in Finder on mac (vit9696)
- MACOS: Fix Finder reveal in preview and torrent contents (vit9696)
- MACOS: Fix cmd+w not closing the main window on macOS (vit9696)
- OTHER: Fix splitting of compiler flags in configure. Autoconf removes a set of [] during script translation, resulting in a wrong sed command. (sledgehammer999)
- OTHER: configure: Parse all compiler related flags together. (sledgehammer999)
- OTHER: Update copyright year. (sledgehammer999)
* Sun Dec 17 2017 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.0.3
- BUGFIX: Add height padding to the transfer list icons. Closes #7951. (sledgehammer999)
- BUGFIX: Allow to drag-n-drop URLs into mainwindow to initiate download. (Chocobo1)
@@ -459,7 +83,7 @@
- BUGFIX: Optimize code for SpeedWidget. (dzmat)
- BUGFIX: Disable processing events when adding torrents(prevents crashes). Closes #7436. (Chocobo1)
- BUGFIX: Open links in browser. Closes #7651. (Chocobo1)
- BUGFIX: Change default settings for tracker/tier announces to mimic μTorrent behavior. (sledgehammer999)
- BUGFIX: Change default settings for tracker/tier announces to mimick μTorrent behavior. (sledgehammer999)
- BUGFIX: Explicitly set UPnP state on start-up. Closes #7338. (Chocobo1)
- BUGFIX: Include/print caught signal in stackdump (Chocobo1)
- COSMETIC: Trackerlist: Set text alignment of columns with numbers to the right (thalieht)
@@ -590,7 +214,7 @@
- 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: Separate seeds from peers for DHT, PeX and LSD (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)
@@ -602,7 +226,7 @@
- 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 comparison for torrent content window. Closes #6327. (Chocobo1)
- 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)
@@ -730,12 +354,12 @@
- FEATURE: Add option to automatically remove .torrent files upon adding (Eugene Shalygin)
- FEATURE: Add option to bind directly to an IP instead of using a network Interface (Sjoerd van der Berg, sledgehammer999)
- FEATURE: Detailed tooltips on the progress and availability bars in the General button of each torrent. (Eugene Shalygin)
- FEATURE: Let user able to specify a filter when choosing an IP filter file (Chocobo1)
- FEATURE: Let user able to specifiy a filter when choosing an IP filter file (Chocobo1)
- FEATURE: Improve usability of "Run External Program". Users can write (platform dependent) shell scripts now. (Chocobo1)
- PERFORMANCE: Optimize drawing in speed graph (Anton Lashkov, Chocobo1)
- BUGFIX: Fix memory leak. (sledgehammer999)
- BUGFIX: Fix resizing bug in "add torrent dialog". Closes #5036. (Chocobo1)
- BUGFIX: Fix qBittorrent doesn't exit immediately when "all downloads are done -> exit" option enabled. (glassez, Chocobo1)
- BUGFIX: Fix qBittorrent doesn't exit immediately when "all donwloads are done -> exit" option enabled. (glassez, Chocobo1)
- BUGFIX: Display the filepath when a torrent fails to load. Closes #100 and #805. (sledgehammer999)
- BUGFIX: Fix Add tracker dialog empty trackers (ngosang)
- BUGFIX: Fix Add tracker dialog URL download (ngosang)
@@ -788,7 +412,7 @@
- OTHER: Enable access to shutdown functions when configured with `--disable-gui` option (Chocobo1)
- OTHER: Delete Import Torrent Dialog. Just use the "add new torrent" dialog. (glassez)
- OTHER: Optimize code for natural sorting (Chocobo1)
- OTHER: Use new alert dispatching API for libtorrent 1.1.x (glassez)
- OTHER: Use new alert dispathing API for libtorrent 1.1.x (glassez)
- OTHER: Fix gcc 6 compilation with qmake. See #5237. (sledgehammer999)
* Tue Mar 29 2016 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.3.4
@@ -1112,7 +736,7 @@
- SEARCH: Fix thepiratebay. Closes #3012 (ngosang)
- SEARCH: Improve torrentz engine to return more results (ngosang)
- SEARCH: Change width of columns in search tab. Closes #764 (ngosang)
- SEARCH: Make strings translatable in search engine (ngosang)
- SEARCH: Make strings translatable in seach engine (ngosang)
- SEARCH: Aborting search engine process during closure. Close #2671 (DoumanAsh)
- SEARCH: Perform searches in parallel (DoumanAsh)
- SEARCH: Add Demonoid search engine (ngosang)
@@ -1279,7 +903,7 @@
- WEBUI: Removed broken 'Documentation'. Improves fix for #1343 (Benjamin Hutchins)
- WEBUI: Removed essentially useless 'Visit website' iframe and changed it to a regular link. Improves fix for #1343 (Benjamin Hutchins)
- BUGFIX: Fix RSS feed icon. The tmp file gets deleted in the feed destructor. Closes #1639 (sledgehammer999)
- BUGFIX: fix issue #1674: AddNewTorrentDialog is shown again and again even if checkbox "don't ask me again" is set (Ivan Sorokin)
- BUGFIX: fix issue #1674: AddNewTorrentDialog is shown again and again even if checkbox "dont ask me again" is set (Ivan Sorokin)
- BUGFIX: Don't show availability bar for magnet links (Ivan Sorokin)
- BUGFIX: Fix crash when the selected torrent disappears from the transfer list. Closes #1661 (sledgehammer999)
- BUGFIX: Fix tracker announcing problem(hit-and-run) when many torrents are being active. Closes #1571 (sledgehammer999)
@@ -1413,7 +1037,7 @@
- FEATURE: Show external IP in the log. Closes #968. (sledgehammer999)
- FEATURE: Enable gzip compression in the webui. It should be faster now. (sledgehammer999)
- FEATURE: Torrents show more states(queued for checking, downloading metadata, allocating, checking resume). (sledgehammer999)
- FEATURE: Re-enable "force reannounce" to all trackers. (sledgehammer999)
- FEATURE: Reenable "force reannounce" to all trackers. (sledgehammer999)
- FEATURE: Allow to clear the UI lock password. Closes #973. (sledgehammer999)
- FEATURE: New translations: English(Australia) and English(United Kingdom)
- BUGFIX: Expose all available translation in the WebUI. Closes #976. (sledgehammer999)
@@ -1462,8 +1086,8 @@
- OTHER: Make peer tab sortable by ip too (Gelmir)
- OTHER: Translations moved to Transifex(https://www.transifex.com/projects/p/qbittorrent/)
- OTHER: New Translation - Vietnamese (Anh Phan)
- PERFORMANCE: Improve drawing speed of tranferlist when there are many torrents(>100)
- PERFORMANCE: Improve drawing speed of peers list when there are many peers
- PERFORMANCE: Impove drawing speed of tranferlist when there are many torrents(>100)
- PERFORMANCE: Impove drawing speed of peers list when there are many peers
* Mon Jul 29 2013 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.0.11
- FEATURE: Allow more fine tuning of upload slots. It should improve speed (sledgehammer999)
@@ -1503,8 +1127,8 @@
- LIBTORRENT: SOCKS5 fixes (0.16.10)
- LIBTORRENT: Fix hanging issue on Windows when closing files (0.16.10)
- LIBTORRENT: Cache can now be returned to the OS (0.16.10)
- PERFORMANCE: Improve drawing speed of tranferlist when there are many torrents(>100) (sledgehammer999)
- PERFORMANCE: Improve drawing speed of peers list when there are many peers (sledgehammer999)
- PERFORMANCE: Impove drawing speed of tranferlist when there are many torrents(>100) (sledgehammer999)
- PERFORMANCE: Impove drawing speed of peers list when there are many peers (sledgehammer999)
* Sat Mar 16 2013 - Christophe Dumez <chris@qbittorrent.org> - v3.0.9
- BUGFIX: Raise qBittorrent windows when another instance is launched
@@ -1528,7 +1152,7 @@
- BUGFIX: Fix "Couldn't set environment variable..." message on start up (closes #245)
- BUGFIX: Use right path separator in torrent addition dialog on Windows
- BUGFIX: Fix "Set as default save path" setting (closes #254)
- BUGFIX: Re-enable disk cache on Windows since the memory issue seems to be gone
- BUGFIX: Reenable disk cache on Windows since the memory issue seems to be gone
- BUGFIX: Fixed several search engine plugins and removed the dead ones
- BUGFIX: Use https links in search plugins when possible
- BUGFIX: Bump Mootools to v1.4.5 (Web UI)
@@ -1664,7 +1288,7 @@
- I18N: Add Georgian translation
* Sat Oct 29 2011 - Christophe Dumez <chris@qbittorrent.org> - v2.9.2
- BUGFIX: Fix minimum dimensions for torrent addition dialog
- BUGFIX: Fix mimimum dimensions for torrent addition dialog
- BUGFIX: Remove dependency on boost-datetime
- BUGFIX: Remove dependency on boost-filesystem (libtorrent v0.16.x)
@@ -1875,7 +1499,7 @@
- BUGFIX: Update RSS feed as soon as feed downloader is enabled
- BUGFIX: RSS Feed downloader ignores articles above maximum number of articles
- BUGFIX: Fix possible bug when deleting a RSS folder
- BUGFIX: Remove persistent data when a RSS feed is deleted
- BUGFIX: Remove persistant data when a RSS feed is deleted
- BUGFIX: RSS filters are now alphabetically sorted
- BUGFIX: Fix crash when renaming currently displayed RSS filter
- BUGFIX: Remove overwriting confirmation when exporting RSS filters since Qt takes care of it
@@ -1911,7 +1535,7 @@
- BUGFIX: Use the save path set in program preferences as a default in torrent addition dialog
* Fri Dec 18 2009 - Christophe Dumez <chris@qbittorrent.org> - v2.0.2
- BUGFIX: Fix .qbittorrent folder not being created (critical bug introduced in v2.0.1 that makes qBittorrent unusable for new users)
- BUGFIX: Fix .qbittorrent folder not being created (critical bug introduced in v2.0.1 that makes qBittorrent unusuable for new users)
- BUGFIX: Fix RSS Feed downloader for some feeds
- BUGFIX: Do not use home folder as a fallback when the save path is not accessible
- BUGFIX: Fix Mininova, ThePirateBay search engine plugins
@@ -2001,7 +1625,7 @@
- BUGFIX: Fix trackers addition to torrents (bug introduced in v1.5.4)
- BUGFIX: Suppress compilation warning regarding sortNewsList() not being used
- BUGFIX: Make sure scan folder is different than qBittorrent backup directory to avoid torrents deletion
- BUGFIX: Added safety mechanism which adds the torrents back to the list in case qbittorrent-resume.conf gets deleted or corrupted.
- BUGFIX: Added safety mecanism which adds the torrents back to the list in case qbittorrent-resume.conf gets deleted or corrupted.
* Sun Oct 25 2009 - Christophe Dumez <chris@qbittorrent.org> - v1.5.4
- BUGFIX: Updated man page
@@ -2068,7 +1692,7 @@
- FEATURE: Added right click menu in search engine to clear completion history
- FEATURE: Allow to set a different port for DHT (UDP) than the one used for Bittorrent
- FEATURE: Updated spoofing code to avoid trackers ban
- BUGFIX: Provide more helpful explanation when an I/O error occurred
- BUGFIX: Provide more helpful explanation when an I/O error occured
- BUGFIX: Stop enforcing UTF-8 and use system locale instead
- COSMETIC: Redesigned program preferences
- COSMETIC: Updated icons set
@@ -2086,7 +1710,7 @@
- BUGFIX: Suppressed QLayout: Attempting to add QLayout "" to properties "properties" warning message when opening a properties dialog
- BUGFIX: Fixed a little bug in search engine plugins helper file
- BUGFIX: Fixed compilation problems with Qt 4.3
- BUGFIX: Percentages no longer disappear with default cleanlooks style
- BUGFIX: Percentages no longer disapear with default cleanlooks style
- BUGFIX: Cleanly fixed popup menus position in lists (no more workarounds)
- BUGFIX: Fixed memory leak in search engine
- BUGFIX: Torrents with an infinite ratio are no longer affected by ratio_limit set in program preferences
@@ -2331,7 +1955,7 @@
- FEATURE: Number of complete/incomplete sources are now displayed in download list for each torrent
- FEATURE: Implemented close to systray
- FEATURE: Added Autocompletion to search engine
- FEATURE: Split BT & GUI parts (huge code rewriting & optimization)
- FEATURE: Splitted BT & GUI parts (huge code rewriting & optimization)
- FEATURE: New parameters for configure file to point to custom locations for libtorrent/libcurl
- FEATURE: Update application style according to the system (WindowsXP, MacOS, X11)
- BUGFIX: Two torrents can now have the same name although they are different (use their hash)

49
INSTALL
View File

@@ -1,49 +1,54 @@
qBittorrent - A BitTorrent client in C++ / Qt
qBittorrent - A BitTorrent client in C++ / Qt4
------------------------------------------
1) Compile and install qBittorrent with Qt graphical interface
1) Compile and install qBittorrent with Qt4 Graphical Interface
$ ./configure
$ make && make install
$ qbittorrent
will install and execute qBittorrent.
will install and execute qBittorrent hopefully without any problems.
Dependencies:
- Qt >= 5.5.1
- Qt >= 4.6.0 (libqtgui, libqtcore, libqtnetwork, libqtxml, libqtdbus/optional)
- pkg-config
- pkg-config executable
- libtorrent-rasterbar >= 1.0.6 (by Arvid Norberg)
* https://www.libtorrent.org/
* Be careful: another library (the one used by rTorrent) uses a similar name
- libtorrent-rasterbar by Arvid Norberg (>= 1.0.6)
-> http://www.libtorrent.net
Be careful: another library (the one used by rTorrent) uses a similar name.
- Boost >= 1.35
- libboost >= 1.35.x (libboost-system)
- Python >= 2.7.9 / 3.3.0 (optional, runtime only)
* Required by the internal search engine
- python >= 2.3 (needed by search engine)
* Run time only dependency
2) Compile and install qBittorrent without Qt graphical interface
- geoip-database (optional)
* If qBittorrent cannot find this database, it will try to resolve countries using the Internet but it will be a lot slower.
* Run time only dependency
2) Compile and install qBittorrent without Qt4 Graphical interface
$ ./configure --disable-gui
$ make && make install
$ qbittorrent-nox
$ qbittorrent
will install and execute qBittorrent.
will install and execute qBittorrent hopefully without any problems.
Dependencies:
- Qt >= 5.5.1
- Qt >= 4.4.0 (libqt-devel, libqtcore, libqtnetwork)
- pkg-config
- pkg-config executable
- libtorrent-rasterbar >= 1.0.6 (by Arvid Norberg)
* https://www.libtorrent.org/
* Be careful: another library (the one used by rTorrent) uses a similar name
- libtorrent-rasterbar by Arvid Norberg (>= v1.0.6)
-> http://www.libtorrent.net
Be careful: another library (the one used by rTorrent) uses a similar name.
- libboost: libboost-filesystem, libboost-date-time, libboost-thread, libboost-serialization
- Boost >= 1.35
DOCUMENTATION:
Please note that there is a "Compilation" section at http://wiki.qbittorrent.org.
Please note that there is a documentation with a "compiling howto" at http://wiki.qbittorrent.org.
------------------------------------------
sledgehammer999 <sledgehammer999@qbittorrent.org>
Christophe Dumez <chris@qbittorrent.org>

View File

@@ -35,7 +35,7 @@ You can also download it from [here](https://github.com/qbittorrent/qBittorrent/
### Misc:
For more information please visit:
https://www.qbittorrent.org
http://www.qbittorrent.org
or our wiki here:
http://wiki.qbittorrent.org

View File

@@ -1,9 +1,9 @@
#! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.
scriptversion=2018-03-07.03; # UTC
scriptversion=2012-10-14.11; # UTC
# Copyright (C) 1999-2018 Free Software Foundation, Inc.
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
@@ -17,7 +17,7 @@ scriptversion=2018-03-07.03; # UTC
# 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, see <https://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
@@ -255,8 +255,7 @@ EOF
echo "compile $scriptversion"
exit $?
;;
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
func_cl_wrapper "$@" # Doesn't return...
;;
esac
@@ -340,9 +339,9 @@ exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'before-save-hook 'time-stamp)
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

966
build-aux/config.guess vendored

File diff suppressed because it is too large Load Diff

2702
build-aux/config.sub vendored

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2018-03-11.20; # UTC
scriptversion=2013-12-25.23; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
@@ -271,18 +271,15 @@ do
fi
dst=$dst_arg
# If destination is a directory, append the input filename.
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test "$is_target_a_directory" = never; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dstbase=`basename "$src"`
case $dst in
*/) dst=$dst$dstbase;;
*) dst=$dst/$dstbase;;
esac
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
dstdir=`dirname "$dst"`
@@ -291,11 +288,6 @@ do
fi
fi
case $dstdir in
*/) dstdirslash=$dstdir;;
*) dstdirslash=$dstdir/;;
esac
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
@@ -332,43 +324,34 @@ do
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
# Note that $RANDOM variable is not portable (e.g. dash); Use it
# here however when possible just to lower collision chance.
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
# Because "mkdir -p" follows existing symlinks and we likely work
# directly in world-writeable /tmp, make sure that the '$tmpdir'
# directory is successfully created first before we actually test
# 'mkdir -p' feature.
if (umask $mkdir_umask &&
$mkdirprog $mkdir_mode "$tmpdir" &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
test_tmpdir="$tmpdir/a"
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi
trap '' 0;;
esac;;
@@ -444,8 +427,8 @@ do
else
# Make a couple of temp file names in the proper directory.
dsttmp=${dstdirslash}_inst.$$_
rmtmp=${dstdirslash}_rm.$$_
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
@@ -510,9 +493,9 @@ do
done
# Local variables:
# eval: (add-hook 'before-save-hook 'time-stamp)
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View File

@@ -1,9 +1,9 @@
#! /bin/sh
# Common wrapper for a few potentially missing GNU programs.
scriptversion=2018-03-07.03; # UTC
scriptversion=2013-10-28.13; # UTC
# Copyright (C) 1996-2018 Free Software Foundation, Inc.
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
@@ -17,7 +17,7 @@ scriptversion=2018-03-07.03; # UTC
# 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, see <https://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
@@ -101,9 +101,9 @@ else
exit $st
fi
perl_URL=https://www.perl.org/
flex_URL=https://github.com/westes/flex
gnu_software_URL=https://www.gnu.org/software
perl_URL=http://www.perl.org/
flex_URL=http://flex.sourceforge.net/
gnu_software_URL=http://www.gnu.org/software
program_details ()
{
@@ -207,9 +207,9 @@ give_advice "$1" | sed -e '1s/^/WARNING: /' \
exit $st
# Local variables:
# eval: (add-hook 'before-save-hook 'time-stamp)
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View File

@@ -1,22 +0,0 @@
# Helper function for coupling add_feature_info(), option(), and add_definitions()
function(optional_compile_definitions _name)
set(options FEATURE)
set(oneValueArgs DESCRIPTION DEFAULT)
set(multiValueArgs ENABLED DISABLED)
cmake_parse_arguments(OCD "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
option(${_name} "${OCD_DESCRIPTION}" ${OCD_DEFAULT})
if (${${_name}})
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY COMPILE_DEFINITIONS ${OCD_ENABLED})
else()
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY COMPILE_DEFINITIONS ${OCD_DISABLED})
endif()
if(${OCD_FEATURE})
add_feature_info(${_name} ${_name} "${OCD_DESCRIPTION}")
endif()
endfunction()
macro(feature_option _name _description _default)
option(${_name} "${_description}" ${_default})
add_feature_info(${_name} ${_name} "${_description}")
endmacro()

View File

@@ -99,7 +99,6 @@ list(FIND LibtorrentRasterbar_DEFINITIONS -DTORRENT_USE_OPENSSL LibtorrentRaster
if(LibtorrentRasterbar_ENCRYPTION_INDEX GREATER -1)
find_package(OpenSSL REQUIRED)
set(LibtorrentRasterbar_LIBRARIES ${LibtorrentRasterbar_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto)
list(APPEND LibtorrentRasterbar_INCLUDE_DIRS "${OPENSSL_INCLUDE_DIR}")
set(LibtorrentRasterbar_OPENSSL_ENABLED ON)
endif()
@@ -114,10 +113,10 @@ mark_as_advanced(LibtorrentRasterbar_INCLUDE_DIR LibtorrentRasterbar_LIBRARY
LibtorrentRasterbar_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES
LibtorrentRasterbar_ENCRYPTION_INDEX)
if (LibtorrentRasterbar_FOUND AND NOT TARGET LibtorrentRasterbar::torrent-rasterbar)
add_library(LibtorrentRasterbar::torrent-rasterbar UNKNOWN IMPORTED)
if (LibtorrentRasterbar_FOUND AND NOT TARGET LibtorrentRasterbar::LibTorrent)
add_library(LibtorrentRasterbar::LibTorrent UNKNOWN IMPORTED)
set_target_properties(LibtorrentRasterbar::torrent-rasterbar PROPERTIES
set_target_properties(LibtorrentRasterbar::LibTorrent PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
IMPORTED_LOCATION "${LibtorrentRasterbar_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${LibtorrentRasterbar_INCLUDE_DIRS}"

View File

@@ -1,79 +1,94 @@
# - Try to find the QtSingleApplication includes and library
# which defines
#
# QtSingleApplication_FOUND - system has QtSingleApplication
# QtSingleApplication_INCLUDE_DIR - where to find header QtSingleApplication
# QtSingleApplication_LIBRARIES - the libraries to link against to use QtSingleApplication
# QtSingleApplication_LIBRARY - where to find the QtSingleApplication library (not for general use)
# QTSINGLEAPPLICATION_FOUND - system has QtSingleApplication
# QTSINGLEAPPLICATION_INCLUDE_DIR - where to find header QtSingleApplication
# QTSINGLEAPPLICATION_LIBRARIES - the libraries to link against to use QtSingleApplication
# QTSINGLEAPPLICATION_LIBRARY - where to find the QtSingleApplication library (not for general use)
# copyright (c) 2013 TI_Eugene ti.eugene@gmail.com
#
# Redistribution and use is allowed according to the terms of the FreeBSD license.
SET(QtSingleApplication_FOUND FALSE)
SET(QTSINGLEAPPLICATION_FOUND FALSE)
if (Qt5Widgets_FOUND)
set(_includeFileName qtsingleapplication.h)
else()
set(_includeFileName qtsinglecoreapplication.h)
endif()
IF(QT4_FOUND)
message(STATUS "Looking for Qt4 single application library")
FIND_PATH(QTSINGLEAPPLICATION_INCLUDE_DIR QtSingleApplication
# standard locations
/usr/include
/usr/include/QtSolutions
# qt4 location except mac's frameworks
"${QT_INCLUDE_DIR}/QtSolutions"
# mac's frameworks
${FRAMEWORK_INCLUDE_DIR}/QtSolutions
)
FOREACH(TOP_INCLUDE_PATH in ${Qt5Core_INCLUDE_DIRS} ${FRAMEWORK_INCLUDE_DIR})
FIND_PATH(QtSingleApplication_INCLUDE_DIR ${_includeFileName} ${TOP_INCLUDE_PATH}/QtSolutions)
SET(QTSINGLEAPPLICATION_NAMES ${QTSINGLEAPPLICATION_NAMES}
QtSolutions_SingleApplication-2.6 libQtSolutions_SingleApplication-2.6)
FIND_LIBRARY(QTSINGLEAPPLICATION_LIBRARY
NAMES ${QTSINGLEAPPLICATION_NAMES}
PATHS ${QT_LIBRARY_DIR}
)
ELSEIF(Qt5Core_FOUND)
message(STATUS "Looking for Qt5 single application library")
FOREACH(TOP_INCLUDE_PATH in ${Qt5Core_INCLUDE_DIRS} ${FRAMEWORK_INCLUDE_DIR})
FIND_PATH(QTSINGLEAPPLICATION_INCLUDE_DIR QtSingleApplication ${TOP_INCLUDE_PATH}/QtSolutions)
IF(QtSingleApplication_INCLUDE_DIR)
BREAK()
ENDIF()
ENDFOREACH()
IF(QTSINGLEAPPLICATION_INCLUDE_DIR)
BREAK()
ENDIF()
ENDFOREACH()
SET(QtSingleApplication_NAMES ${QtSingleApplication_NAMES}
Qt5Solutions_SingleApplication-2.6 libQt5Solutions_SingleApplication-2.6
QtSolutions_SingleApplication-2.6 libQtSolutions_SingleApplication-2.6)
GET_TARGET_PROPERTY(_QT5_CORELIBRARY Qt5::Core LOCATION)
GET_FILENAME_COMPONENT(_QT5_CORELIBRARYPATH ${_QT5_CORELIBRARY} PATH)
SET(QTSINGLEAPPLICATION_NAMES ${QTSINGLEAPPLICATION_NAMES}
Qt5Solutions_SingleApplication-2.6 libQt5Solutions_SingleApplication-2.6
QtSolutions_SingleApplication-2.6 libQtSolutions_SingleApplication-2.6)
GET_TARGET_PROPERTY(_QT5_CORELIBRARY Qt5::Core LOCATION)
GET_FILENAME_COMPONENT(_QT5_CORELIBRARYPATH ${_QT5_CORELIBRARY} PATH)
FIND_LIBRARY(QtSingleApplication_LIBRARY
NAMES ${QtSingleApplication_NAMES}
PATHS ${_QT5_CORELIBRARYPATH}
)
FIND_LIBRARY(QTSINGLEAPPLICATION_LIBRARY
NAMES ${QTSINGLEAPPLICATION_NAMES}
PATHS ${_QT5_CORELIBRARYPATH}
)
ENDIF()
IF (QtSingleApplication_LIBRARY AND QtSingleApplication_INCLUDE_DIR)
IF (QTSINGLEAPPLICATION_LIBRARY AND QTSINGLEAPPLICATION_INCLUDE_DIR)
SET(QtSingleApplication_LIBRARIES ${QtSingleApplication_LIBRARY})
SET(QtSingleApplication_FOUND TRUE)
SET(QTSINGLEAPPLICATION_LIBRARIES ${QTSINGLEAPPLICATION_LIBRARY})
SET(QTSINGLEAPPLICATION_FOUND TRUE)
IF (CYGWIN)
IF(BUILD_SHARED_LIBS)
# No need to define QtSingleApplication_USE_DLL here, because it's default for Cygwin.
# No need to define QTSINGLEAPPLICATION_USE_DLL here, because it's default for Cygwin.
ELSE(BUILD_SHARED_LIBS)
SET (QtSingleApplication_DEFINITIONS -DQTSINGLEAPPLICATION_STATIC)
SET (QTSINGLEAPPLICATION_DEFINITIONS -DQTSINGLEAPPLICATION_STATIC)
ENDIF(BUILD_SHARED_LIBS)
ENDIF (CYGWIN)
ENDIF (QtSingleApplication_LIBRARY AND QtSingleApplication_INCLUDE_DIR)
ENDIF (QTSINGLEAPPLICATION_LIBRARY AND QTSINGLEAPPLICATION_INCLUDE_DIR)
IF (QtSingleApplication_FOUND)
IF (NOT QtSingleApplication_FIND_QUIETLY)
MESSAGE(STATUS "Found QtSingleApplication: ${QtSingleApplication_LIBRARY}")
MESSAGE(STATUS " includes: ${QtSingleApplication_INCLUDE_DIR}")
ENDIF (NOT QtSingleApplication_FIND_QUIETLY)
if(NOT TARGET QtSingleApplication::QtSingleApplication)
add_library(QtSingleApplication::QtSingleApplication UNKNOWN IMPORTED)
set_target_properties(QtSingleApplication::QtSingleApplication PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${QtSingleApplication_INCLUDE_DIR}"
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${QtSingleApplication_INCLUDE_DIR}"
)
if(EXISTS "${QtSingleApplication_LIBRARY}")
set_target_properties(QtSingleApplication::QtSingleApplication PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
IMPORTED_LOCATION "${QtSingleApplication_LIBRARY}")
endif()
endif(NOT TARGET QtSingleApplication::QtSingleApplication)
ELSE (QtSingleApplication_FOUND)
IF (QTSINGLEAPPLICATION_FOUND)
IF (NOT QtSingleApplication_FIND_QUIETLY)
MESSAGE(STATUS "Found QtSingleApplication: ${QTSINGLEAPPLICATION_LIBRARY}")
MESSAGE(STATUS " includes: ${QTSINGLEAPPLICATION_INCLUDE_DIR}")
ENDIF (NOT QtSingleApplication_FIND_QUIETLY)
ELSE (QTSINGLEAPPLICATION_FOUND)
IF (QtSingleApplication_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find QtSingleApplication library")
ENDIF (QtSingleApplication_FIND_REQUIRED)
ENDIF (QtSingleApplication_FOUND)
ENDIF (QTSINGLEAPPLICATION_FOUND)
MARK_AS_ADVANCED(QtSingleApplication_INCLUDE_DIR QtSingleApplication_LIBRARY)
MARK_AS_ADVANCED(QTSINGLEAPPLICATION_INCLUDE_DIR QTSINGLEAPPLICATION_LIBRARY)
if(NOT TARGET QtSingleApplication::QtSingleApplication)
add_library(QtSingleApplication::QtSingleApplication UNKNOWN IMPORTED)
set_target_properties(QtSingleApplication::QtSingleApplication PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${QTSINGLEAPPLICATION_INCLUDE_DIR}"
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${QTSINGLEAPPLICATION_INCLUDE_DIR}"
)
if(EXISTS "${QTSINGLEAPPLICATION_LIBRARY}")
set_target_properties(QtSingleApplication::QtSingleApplication PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
IMPORTED_LOCATION "${QTSINGLEAPPLICATION_LIBRARY}")
endif()
endif(NOT TARGET QtSingleApplication::QtSingleApplication)

View File

@@ -1,5 +1,5 @@
# - macro similar to target_link_libraries, which links Qt components
# names of the components are passed in Qt4/Qt5 agnostic way (Core, DBus, Xml...)
# names of the components are pased in Qt4/Qt5 agnostic way (Core, DBus, Xml...)
# and the macro links Qt4 ones if QT4_FOUND is set or Qt5 ones if not
macro (target_link_qt_components target)

View File

@@ -11,17 +11,18 @@ macro(qbt_set_compiler_options)
#-Wshadow -Wconversion ?
set(_GCC_COMMON_C_AND_CXX_FLAGS "-Wall -Wextra"
"-Wfloat-equal -Wcast-qual -Wcast-align"
"-Wsign-conversion -Winvalid-pch -Wno-long-long"
#"-fstack-protector-all"
#"-Werror -Wno-error=deprecated-declarations"
"-Wsign-conversion -Winvalid-pch -Werror=return-type -Wno-long-long"
# -fstack-protector-all
"-Werror -Wno-error=deprecated-declarations"
)
set(_GCC_COMMON_CXX_FLAGS "-fexceptions -frtti"
"-Woverloaded-virtual -Wold-style-cast"
set (_GCC_COMMON_CXX_FLAGS "-fexceptions -frtti"
"-Woverloaded-virtual -Wold-style-cast -Wstrict-null-sentinel"
"-Wnon-virtual-dtor -Wfloat-equal -Wcast-qual -Wcast-align"
#"-Weffc++"
#"-Werror -Wno-error=cpp"
"-Werror=overloaded-virtual"
# "-Weffc++"
"-Werror -Wno-error=cpp"
# we should modify code to make these ones obsolete
#"-Wno-error=sign-conversion -Wno-error=float-equal"
"-Wno-error=sign-conversion -Wno-error=float-equal"
)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
@@ -53,20 +54,6 @@ macro(qbt_set_compiler_options)
endif(${GLIBC_VERSION})
endif (CMAKE_SYSTEM_NAME MATCHES Linux)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# Clang 5.0 still doesn't support -Wstrict-null-sentinel
check_cxx_compiler_flag(-Wstrict-null-sentinel _STRICT_NULL_SENTINEL_IS_SUPPORTED)
if (_STRICT_NULL_SENTINEL_IS_SUPPORTED)
list(APPEND _GCC_COMMON_CXX_FLAGS "-Wstrict-null-sentinel")
endif (_STRICT_NULL_SENTINEL_IS_SUPPORTED)
# Code should be improved to render this not needed
list(APPEND _GCC_COMMON_CXX_FLAGS "-Wno-error=unused-function -Wno-error=inconsistent-missing-override")
else ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# GCC supports it
list(APPEND _GCC_COMMON_CXX_FLAGS "-Wstrict-null-sentinel")
endif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
string(REPLACE ";" " " _GCC_COMMON_C_AND_CXX_FLAGS_STRING "${_GCC_COMMON_C_AND_CXX_FLAGS}")
string(REPLACE ";" " " _GCC_COMMON_CXX_FLAGS_STRING "${_GCC_COMMON_CXX_FLAGS}")

View File

@@ -1,17 +1,16 @@
# a helper function which appends source to the target
# sources file names are relative to the the target source dir
# a helper function which appends source to the main qBt target
# sources file names are relative to the the ${qBittorrent_SOURCE_DIR}
function (qbt_target_sources _target _scope)
get_target_property(targetSourceDir ${_target} SOURCE_DIR)
set(sourcesRelative "")
foreach(source IN ITEMS ${ARGN})
if(IS_ABSOLUTE "${source}")
set(sourceAbsolutePath "${source}")
function (qbt_target_sources)
set (_sources_rel "")
foreach (_source IN ITEMS ${ARGN})
if (IS_ABSOLUTE "${_source}")
set(source_abs "${_source}")
else()
get_filename_component(sourceAbsolutePath "${source}" ABSOLUTE)
get_filename_component(_source_abs "${_source}" ABSOLUTE)
endif()
file(RELATIVE_PATH sourceRelativePath "${targetSourceDir}" "${sourceAbsolutePath}")
list(APPEND sourcesRelative "${sourceRelativePath}")
file (RELATIVE_PATH _source_rel "${qbt_executable_SOURCE_DIR}" "${_source_abs}")
list (APPEND _sources_rel "${_source_rel}")
endforeach()
target_sources(${_target} ${_scope} "${sourcesRelative}")
endfunction(qbt_target_sources)
target_sources (qBittorrent PRIVATE "${_sources_rel}")
endfunction (qbt_target_sources)

View File

@@ -1,48 +0,0 @@
# macros to handle translation files
# qbt_add_translations(<target> QRC_FILE <filename> TS_FILES <filenames>)
# handles out of source builds for Qt resource files that include translations
# The function generates translations out of the supplied list of .ts files in the build directory,
# copies the .qrc file there, calls qt5_add_resources() adds its output to the target sources list.
function(qbt_add_translations _target)
set(oneValueArgs QRC_FILE)
set(multiValueArgs TS_FILES)
cmake_parse_arguments(QBT_TR "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
get_target_property(_binaryDir ${_target} BINARY_DIR)
if (NOT QBT_TR_QRC_FILE)
message(FATAL_ERROR "QRC file is empty")
endif()
if (NOT QBT_TR_TS_FILES)
message(FATAL_ERROR "TS_FILES files are empty")
endif()
if(IS_ABSOLUTE "${QBT_TR_QRC_FILE}")
file(RELATIVE_PATH _qrcToTs "${CMAKE_CURRENT_SOURCE_DIR}" "${QBT_TR_QRC_FILE}")
else()
set(_qrcToTs "${QBT_TR_QRC_FILE}")
endif()
get_filename_component(_qrcToTsDir "${_qrcToTs}" DIRECTORY)
get_filename_component(_qmFilesBinaryDir "${CMAKE_CURRENT_BINARY_DIR}/${_qrcToTsDir}" ABSOLUTE)
# to make qt5_add_translation() work as we need
set_source_files_properties(${QBT_TR_TS_FILES} PROPERTIES OUTPUT_LOCATION "${_qmFilesBinaryDir}")
qt5_add_translation(_qmFiles ${QBT_TR_TS_FILES})
set(_qrc_dest_dir "${_binaryDir}/${_qrcToTsDir}")
set(_qrc_dest_file "${_binaryDir}/${QBT_TR_QRC_FILE}")
message(STATUS "copying ${QBT_TR_QRC_FILE} to ${_qrc_dest_dir}")
file(COPY ${QBT_TR_QRC_FILE} DESTINATION ${_qrc_dest_dir})
set_source_files_properties("${_qrc_dest_file}" PROPERTIES
GENERATED True
OBJECT_DEPENDS "${_qmFiles}")
# With AUTORCC enabled rcc is ran by cmake before language files are generated,
# and thus we call rcc explicitly
qt5_add_resources(_resources "${_qrc_dest_file}")
target_sources(${_target} PRIVATE "${_resources}")
endfunction()

View File

@@ -1,9 +1,9 @@
if (STACKTRACE)
if (STACKTRACE_WIN)
if ("${WINXXBITS}" NOT STREQUAL "Win64")
add_compile_options(-fno-omit-frame-pointer)
endif ("${WINXXBITS}" NOT STREQUAL "Win64")
link_libraries(libdbghelp -Wl,--export-all-symbols)
endif (STACKTRACE)
endif (STACKTRACE_WIN)
if (("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") OR ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo"))
link_libraries(-Wl,--dynamicbase)

View File

@@ -1,4 +1,4 @@
if (STACKTRACE)
if (STACKTRACE_WIN)
if ("${WINXXBITS}" STREQUAL "Win64")
add_compile_options(-Zi)
else ("${WINXXBITS}" STREQUAL "Win64")
@@ -6,7 +6,7 @@ if (STACKTRACE)
add_compile_options(-Oy-)
endif ("${WINXXBITS}" STREQUAL "Win64")
link_libraries(dbghelp.lib)
endif (STACKTRACE)
endif (STACKTRACE_WIN)
# Enable Wide characters
add_definitions(-DTORRENT_USE_WPATH)

View File

@@ -5,8 +5,6 @@ BINDIR = @EXPAND_BINDIR@
DATADIR = @EXPAND_DATADIR@
MANPREFIX = @EXPAND_MANDIR@
QMAKE_CC = @QBT_CC@
QMAKE_CXX = @QBT_CXX@
QMAKE_CXXFLAGS += @QBT_CONF_EXTRA_CFLAGS@
EXTERNAL_INCLUDES = @QBT_CONF_INCLUDES@

View File

@@ -50,8 +50,6 @@ DEFINES += BOOST_USE_WINAPI_VERSION=0x0501
#DEFINES += BOOST_ASIO_SEPARATE_COMPILATION
# Enable if building against libtorrent 1.0.x (RC_1_0) (dynamic linking)
#DEFINES += BOOST_ASIO_DYN_LINK
# Enable if encountered build error with boost version <= 1.59
#DEFINES += BOOST_NO_CXX11_RVALUE_REFERENCES
# Enable if building against libtorrent 1.1.x (RC_1_1)
# built with this flag defined
@@ -60,10 +58,4 @@ DEFINES += BOOST_USE_WINAPI_VERSION=0x0501
#DEFINES += TORRENT_LINKING_SHARED
# Enable stack trace support
CONFIG += stacktrace
win32-msvc* {
QMAKE_CXXFLAGS += "/guard:cf"
QMAKE_LFLAGS += "/guard:cf"
QMAKE_LFLAGS_RELEASE += "/OPT:REF /OPT:ICF"
}
CONFIG += strace_win

562
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for qbittorrent v4.1.9.1.
# Generated by GNU Autoconf 2.69 for qbittorrent v3.2.0alpha.
#
# Report bugs to <bugs.qbittorrent.org>.
#
@@ -580,10 +580,10 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='qbittorrent'
PACKAGE_TARNAME='qbittorrent'
PACKAGE_VERSION='v4.1.9.1'
PACKAGE_STRING='qbittorrent v4.1.9.1'
PACKAGE_VERSION='v3.2.0alpha'
PACKAGE_STRING='qbittorrent v3.2.0alpha'
PACKAGE_BUGREPORT='bugs.qbittorrent.org'
PACKAGE_URL='https://www.qbittorrent.org/'
PACKAGE_URL='http://www.qbittorrent.org/'
ac_subst_vars='am__EXEEXT_FALSE
am__EXEEXT_TRUE
@@ -595,8 +595,6 @@ QBT_REMOVE_CONFIG
QBT_ADD_CONFIG
QBT_CONF_EXTRA_CFLAGS
QBT_CONF_INCLUDES
QBT_CXX
QBT_CC
EXPAND_MANDIR
EXPAND_DATADIR
EXPAND_BINDIR
@@ -628,6 +626,7 @@ am__nodep
AMDEPBACKSLASH
AMDEP_FALSE
AMDEP_TRUE
am__quote
am__include
DEPDIR
am__untar
@@ -691,7 +690,6 @@ infodir
docdir
oldincludedir
includedir
runstatedir
localstatedir
sharedstatedir
sysconfdir
@@ -710,8 +708,7 @@ PACKAGE_VERSION
PACKAGE_TARNAME
PACKAGE_NAME
PATH_SEPARATOR
SHELL
am__quote'
SHELL'
ac_subst_files=''
ac_user_opts='
enable_option_checking
@@ -719,7 +716,6 @@ enable_dependency_tracking
enable_silent_rules
with_qtsingleapplication
enable_debug
enable_stacktrace
enable_gui
enable_systemd
enable_webui
@@ -787,7 +783,6 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1040,15 +1035,6 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
-runstatedir | --runstatedir | --runstatedi | --runstated \
| --runstate | --runstat | --runsta | --runst | --runs \
| --run | --ru | --r)
ac_prev=runstatedir ;;
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
| --run=* | --ru=* | --r=*)
runstatedir=$ac_optarg ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1186,7 +1172,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
libdir localedir mandir runstatedir
libdir localedir mandir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@@ -1299,7 +1285,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures qbittorrent v4.1.9.1 to adapt to many kinds of systems.
\`configure' configures qbittorrent v3.2.0alpha to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1339,7 +1325,6 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@@ -1370,7 +1355,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of qbittorrent v4.1.9.1:";;
short | recursive ) echo "Configuration of qbittorrent v3.2.0alpha:";;
esac
cat <<\_ACEOF
@@ -1385,7 +1370,6 @@ Optional Features:
--enable-silent-rules less verbose build output (undo: "make V=1")
--disable-silent-rules verbose build output (undo: "make V=0")
--enable-debug Enable debug build
--enable-stacktrace Enable stacktrace feature (default=auto)
--disable-gui Disable the GUI for headless running. Disables
QtDBus and the GeoIP Database.
--enable-systemd Install the systemd service file (headless only).
@@ -1442,7 +1426,7 @@ Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
Report bugs to <bugs.qbittorrent.org>.
qbittorrent home page: <https://www.qbittorrent.org/>.
qbittorrent home page: <http://www.qbittorrent.org/>.
_ACEOF
ac_status=$?
fi
@@ -1505,7 +1489,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
qbittorrent configure v4.1.9.1
qbittorrent configure v3.2.0alpha
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1644,7 +1628,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by qbittorrent $as_me v4.1.9.1, which was
It was created by qbittorrent $as_me v3.2.0alpha, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -3276,7 +3260,7 @@ IFS=$ac_save_IFS
case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
am__api_version='1.16'
am__api_version='1.15'
# Find a good install program. We prefer a C program (faster),
# so one script is as good as another. But avoid the broken or
@@ -3702,45 +3686,45 @@ DEPDIR="${am__leading_dot}deps"
ac_config_commands="$ac_config_commands depfiles"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5
$as_echo_n "checking whether ${MAKE-make} supports the include directive... " >&6; }
cat > confinc.mk << 'END'
am_make=${MAKE-make}
cat > confinc << 'END'
am__doit:
@echo this is the am__doit target >confinc.out
@echo this is the am__doit target
.PHONY: am__doit
END
# If we don't find an include directive, just comment out the code.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
$as_echo_n "checking for style of include used by $am_make... " >&6; }
am__include="#"
am__quote=
# BSD make does it like this.
echo '.include "confinc.mk" # ignored' > confmf.BSD
# Other make implementations (GNU, Solaris 10, AIX) do it like this.
echo 'include confinc.mk # ignored' > confmf.GNU
_am_result=no
for s in GNU BSD; do
{ echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5
(${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }
case $?:`cat confinc.out 2>/dev/null` in #(
'0:this is the am__doit target') :
case $s in #(
BSD) :
am__include='.include' am__quote='"' ;; #(
*) :
am__include='include' am__quote='' ;;
esac ;; #(
*) :
;;
_am_result=none
# First try GNU make style include.
echo "include confinc" > confmf
# Ignore all kinds of additional output from 'make'.
case `$am_make -s -f confmf 2> /dev/null` in #(
*the\ am__doit\ target*)
am__include=include
am__quote=
_am_result=GNU
;;
esac
if test "$am__include" != "#"; then
_am_result="yes ($s style)"
break
fi
done
rm -f confinc.* confmf.*
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5
$as_echo "${_am_result}" >&6; }
# Now try BSD make style include.
if test "$am__include" = "#"; then
echo '.include "confinc"' > confmf
case `$am_make -s -f confmf 2> /dev/null` in #(
*the\ am__doit\ target*)
am__include=.include
am__quote="\""
_am_result=BSD
;;
esac
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
$as_echo "$_am_result" >&6; }
rm -f confinc confmf
# Check whether --enable-dependency-tracking was given.
if test "${enable_dependency_tracking+set}" = set; then :
@@ -3822,7 +3806,7 @@ fi
# Define the identity of the package.
PACKAGE='qbittorrent'
VERSION='v4.1.9.1'
VERSION='v3.2.0alpha'
cat >>confdefs.h <<_ACEOF
@@ -3852,8 +3836,8 @@ MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
# For better backward compatibility. To be removed once Automake 1.9.x
# dies out for good. For more background, see:
# <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
# <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
mkdir_p='$(MKDIR_P)'
# We need awk for the "check" target (and possibly the TAP driver). The
@@ -4160,7 +4144,7 @@ END
Aborting the configuration process, to ensure you take notice of the issue.
You can download and install GNU coreutils to get an 'rm' implementation
that behaves properly: <https://www.gnu.org/software/coreutils/>.
that behaves properly: <http://www.gnu.org/software/coreutils/>.
If you want to complete the configuration process using your problematic
'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
@@ -4172,12 +4156,11 @@ END
fi
# use compiler from env variables if available
QBT_CC="$CC"
QBT_CXX="$CXX"
# Define --wth-* and --enable-* arguments
# Check whether --with-qtsingleapplication was given.
if test "${with_qtsingleapplication+set}" = set; then :
withval=$with_qtsingleapplication;
@@ -4194,14 +4177,6 @@ else
fi
# Check whether --enable-stacktrace was given.
if test "${enable_stacktrace+set}" = set; then :
enableval=$enable_stacktrace;
else
enable_stacktrace=auto
fi
# Check whether --enable-gui was given.
if test "${enable_gui+set}" = set; then :
enableval=$enable_gui;
@@ -4402,39 +4377,6 @@ $as_echo "$enable_debug" >&6; }
as_fn_error $? "Unknown option \"$enable_debug\". Use either \"yes\" or \"no\"." "$LINENO" 5 ;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable the stacktrace feature" >&5
$as_echo_n "checking whether to enable the stacktrace feature... " >&6; }
case "x$enable_stacktrace" in #(
"xno") :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
QBT_REMOVE_CONFIG="$QBT_REMOVE_CONFIG stacktrace" ;; #(
"xyes") :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
QBT_ADD_CONFIG="$QBT_ADD_CONFIG stacktrace" ;; #(
"xauto") :
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <execinfo.h>
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
QBT_ADD_CONFIG="$QBT_ADD_CONFIG stacktrace"
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
QBT_REMOVE_CONFIG="$QBT_REMOVE_CONFIG stacktrace"
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ;; #(
*) :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_stacktrace" >&5
$as_echo "$enable_stacktrace" >&6; }
as_fn_error $? "Unknown option \"$enable_stacktrace\". Use either \"yes\" or \"no\"." "$LINENO" 5 ;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable the GUI" >&5
$as_echo_n "checking whether to enable the GUI... " >&6; }
case "x$enable_gui" in #(
@@ -4682,6 +4624,7 @@ esac
# Check whether --with-boost was given.
if test "${with_boost+set}" = set; then :
withval=$with_boost;
@@ -4748,9 +4691,7 @@ fi
case ${host_cpu} in #(
x86_64) :
libsubdirs="lib64 libx32 lib lib64" ;; #(
mips*64*) :
libsubdirs="lib64 lib32 lib lib64" ;; #(
ppc64|powerpc64|s390x|sparc64|aarch64|ppc64le|powerpc64le|riscv64) :
ppc64|s390x|sparc64|aarch64|ppc64le) :
libsubdirs="lib64 lib lib64" ;; #(
*) :
libsubdirs="lib"
@@ -5002,10 +4943,10 @@ $as_echo "$as_me: Your boost libraries seems to old (version $_version)." >&6;}
$as_echo "#define HAVE_BOOST /**/" >>confdefs.h
# execute ACTION-IF-FOUND (if present):
{ $as_echo "$as_me:${as_lineno-$LINENO}: Boost CXXFLAGS: \"$BOOST_CPPFLAGS\"" >&5
$as_echo "$as_me: Boost CXXFLAGS: \"$BOOST_CPPFLAGS\"" >&6;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: Boost LDFLAGS: \"$BOOST_LDFLAGS\"" >&5
$as_echo "$as_me: Boost LDFLAGS: \"$BOOST_LDFLAGS\"" >&6;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: Boost CPPFLAGS: \"$BOOST_CPPFLAGS\"
Boost LDFLAGS: \"$BOOST_LDFLAGS\"" >&5
$as_echo "$as_me: Boost CPPFLAGS: \"$BOOST_CPPFLAGS\"
Boost LDFLAGS: \"$BOOST_LDFLAGS\"" >&6;}
fi
CPPFLAGS="$CPPFLAGS_SAVED"
@@ -5016,31 +4957,9 @@ fi
CXXFLAGS="$BOOST_CPPFLAGS $CXXFLAGS"
CPPFLAGS="$BOOST_CPPFLAGS $CPPFLAGS"
LDFLAGS="$BOOST_LDFLAGS $LDFLAGS"
# add workaround for problematic boost version
# taken from ax_boost_base.m4
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <boost/version.hpp>
int
main ()
{
(void) ((void)sizeof(char[1 - 2*!!((BOOST_VERSION) < (106000))]));
;
return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
else
QBT_ADD_DEFINES="$QBT_ADD_DEFINES BOOST_NO_CXX11_RVALUE_REFERENCES"
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
# Check whether --with-boost-system was given.
@@ -5272,7 +5191,7 @@ fi
fi
if test "x$ax_lib" = "x"; then
as_fn_error $? "Could not find a version of the Boost::System library!" "$LINENO" 5
as_fn_error $? "Could not find a version of the library!" "$LINENO" 5
fi
if test "x$link_system" = "xno"; then
as_fn_error $? "Could not link against $ax_lib !" "$LINENO" 5
@@ -5393,7 +5312,7 @@ else
libtorrent_LIBS=$pkg_cv_libtorrent_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
CXXFLAGS="$libtorrent_CFLAGS $CXXFLAGS"
CPPFLAGS="$libtorrent_CFLAGS $CPPFLAGS"
LIBS="$libtorrent_LIBS $LIBS"
fi
@@ -5486,116 +5405,10 @@ else
zlib_LIBS=$pkg_cv_zlib_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
CXXFLAGS="$zlib_CFLAGS $CXXFLAGS"
CPPFLAGS="$zlib_CFLAGS $CPPFLAGS"
LIBS="$zlib_LIBS $LIBS"
fi
# Check if already in >= C++11 mode because of the flags returned by one of the above packages
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler is using C++11 or later mode" >&5
$as_echo_n "checking if compiler is using C++11 or later mode... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201103L
#error "This is not a C++11 compiler"
#endif
int
main ()
{
;
return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
QBT_CXX11_FOUND="yes"
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
QBT_CXX11_FOUND="no"
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
# In case of no, check if the compiler can support at least C++11
# and if yes, enable it leaving a warning to the user
if test "x$QBT_CXX11_FOUND" = "xno"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler supports C++11" >&5
$as_echo_n "checking if compiler supports C++11... " >&6; }
TMP_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS -std=c++11"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201103L
#error "This is not a C++11 compiler"
#endif
int
main ()
{
;
return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if C++11 is disabled by the set compiler flags" >&5
$as_echo_n "checking if C++11 is disabled by the set compiler flags... " >&6; }
# prepend the flag so it won't override conflicting user defined flags
CXXFLAGS="-std=c++11 $TMP_CXXFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201103L
#error "This is not a C++11 compiler"
#endif
int
main ()
{
;
return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
CXXFLAGS="$TMP_CXXFLAGS -std=c++11"
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C++11 mode is now force enabled.
Make sure you use the same C++ mode for qBittorrent and its dependencies.
To explicitly set qBittorrent to a later mode use CXXFLAGS.
Example: \`CXXFLAGS=\"\$CXXFLAGS -std=c++14\" ./configure\`" >&5
$as_echo "$as_me: WARNING: C++11 mode is now force enabled.
Make sure you use the same C++ mode for qBittorrent and its dependencies.
To explicitly set qBittorrent to a later mode use CXXFLAGS.
Example: \`CXXFLAGS=\"\$CXXFLAGS -std=c++14\" ./configure\`" >&2;}
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
as_fn_error $? "The compiler supports C++11 but the user or a dependency has explicitly enabled a lower mode." "$LINENO" 5
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
as_fn_error $? "A compiler supporting C++11 is required." "$LINENO" 5
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
# These are required because autoconf doesn't expand these **particular**
# vars automatically. And qmake cannot autoexpand them.
@@ -5676,22 +5489,23 @@ extract() {
new_line='
'
# Convert " -" to "\n" if not between quotes and remove possible leading white spaces
string=$(echo " $*" | $SED -e "s: -:\\${new_line}:g" -e 's:"\(.*\)\n\(.*\)":\"\1 -\2":g' -e "s:'\(.*\)\n\(.*\)':\'\1 -\2':g" -e 's/^[[:space:]]*//')
string=$(echo " $*" | $SED -e "s: -:\\${new_line}:g" -e 's:"\(.*\)\n\(.*\)":\"\1 -\2":g' -e "s:'\(.*\)\n\(.*\)':\'\1 -\2':g" -e 's/^[:space:]*//')
SAVEIFS=$IFS
IFS=$(printf "\n\b")
for i in $string; do
case "$(echo "$i" | cut -c1)" in
'') ;;
D) QBT_CONF_DEFINES="$QBT_CONF_DEFINES $(echo $i | cut -c2-)";;
I) QBT_CONF_INCLUDES="$QBT_CONF_INCLUDES $(echo $i | cut -c2-)";;
*) QBT_CONF_EXTRA_CFLAGS="$QBT_CONF_EXTRA_CFLAGS -$i";;
D) QBT_CONF_DEFINES="$(echo $i | cut -c2-) $QBT_CONF_DEFINES";;
I) QBT_CONF_INCLUDES="$(echo $i | cut -c2-) $QBT_CONF_INCLUDES";;
*) QBT_CONF_EXTRA_CFLAGS="-$i $QBT_CONF_EXTRA_CFLAGS";;
esac
done
IFS=$SAVEIFS
}
extract "$CFLAGS $CXXFLAGS"
extract $CPPFLAGS
QBT_ADD_DEFINES="$QBT_ADD_DEFINES $QBT_CONF_DEFINES"
QBT_CONF_EXTRA_CFLAGS="$QBT_CONF_EXTRA_CFLAGS $CXXFLAGS"
# Substitute the values of these vars in conf.pri.in
@@ -5701,8 +5515,6 @@ QBT_ADD_DEFINES="$QBT_ADD_DEFINES $QBT_CONF_DEFINES"
ac_config_files="$ac_config_files conf.pri"
cat >confcache <<\_ACEOF
@@ -6275,7 +6087,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by qbittorrent $as_me v4.1.9.1, which was
This file was extended by qbittorrent $as_me v3.2.0alpha, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -6327,13 +6139,13 @@ Configuration commands:
$config_commands
Report bugs to <bugs.qbittorrent.org>.
qbittorrent home page: <https://www.qbittorrent.org/>."
qbittorrent home page: <http://www.qbittorrent.org/>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
qbittorrent config.status v4.1.9.1
qbittorrent config.status v3.2.0alpha
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
@@ -6441,7 +6253,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
#
# INIT-COMMANDS
#
AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"
AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
_ACEOF
@@ -6886,35 +6698,29 @@ $as_echo "$as_me: executing $ac_file commands" >&6;}
# Older Autoconf quotes --file arguments for eval, but not when files
# are listed without --file. Let's play safe and only enable the eval
# if we detect the quoting.
# TODO: see whether this extra hack can be removed once we start
# requiring Autoconf 2.70 or later.
case $CONFIG_FILES in #(
*\'*) :
eval set x "$CONFIG_FILES" ;; #(
*) :
set x $CONFIG_FILES ;; #(
*) :
;;
esac
case $CONFIG_FILES in
*\'*) eval set x "$CONFIG_FILES" ;;
*) set x $CONFIG_FILES ;;
esac
shift
# Used to flag and report bootstrapping failures.
am_rc=0
for am_mf
for mf
do
# Strip MF so we end up with the name of the file.
am_mf=`$as_echo "$am_mf" | sed -e 's/:.*$//'`
# Check whether this is an Automake generated Makefile which includes
# dependency-tracking related rules and includes.
# Grep'ing the whole file directly is not great: AIX grep has a line
mf=`echo "$mf" | sed -e 's/:.*$//'`
# Check whether this is an Automake generated Makefile or not.
# We used to match only the files named 'Makefile.in', but
# some people rename them; so instead we look at the file content.
# Grep'ing the first line is not enough: some people post-process
# each Makefile.in and add a new line on top of each file to say so.
# Grep'ing the whole file is not good either: AIX grep has a line
# limit of 2048, but all sed's we know have understand at least 4000.
sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \
|| continue
am_dirpart=`$as_dirname -- "$am_mf" ||
$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$am_mf" : 'X\(//\)[^/]' \| \
X"$am_mf" : 'X\(//\)$' \| \
X"$am_mf" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$am_mf" |
if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
dirpart=`$as_dirname -- "$mf" ||
$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$mf" : 'X\(//\)[^/]' \| \
X"$mf" : 'X\(//\)$' \| \
X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$mf" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
@@ -6932,48 +6738,53 @@ $as_echo X"$am_mf" |
q
}
s/.*/./; q'`
am_filepart=`$as_basename -- "$am_mf" ||
$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \
X"$am_mf" : 'X\(//\)$' \| \
X"$am_mf" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X/"$am_mf" |
sed '/^.*\/\([^/][^/]*\)\/*$/{
else
continue
fi
# Extract the definition of DEPDIR, am__include, and am__quote
# from the Makefile without running 'make'.
DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
test -z "$DEPDIR" && continue
am__include=`sed -n 's/^am__include = //p' < "$mf"`
test -z "$am__include" && continue
am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
# Find all dependency output files, they are included files with
# $(DEPDIR) in their names. We invoke sed twice because it is the
# simplest approach to changing $(DEPDIR) to its actual value in the
# expansion.
for file in `sed -n "
s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
# Make sure the directory exists.
test -f "$dirpart/$file" && continue
fdir=`$as_dirname -- "$file" ||
$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$file" : 'X\(//\)[^/]' \| \
X"$file" : 'X\(//\)$' \| \
X"$file" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$file" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\/\(\/\/\)$/{
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\/\(\/\).*/{
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'`
{ echo "$as_me:$LINENO: cd "$am_dirpart" \
&& sed -e '/# am--include-marker/d' "$am_filepart" \
| $MAKE -f - am--depfiles" >&5
(cd "$am_dirpart" \
&& sed -e '/# am--include-marker/d' "$am_filepart" \
| $MAKE -f - am--depfiles) >&5 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } || am_rc=$?
as_dir=$dirpart/$fdir; as_fn_mkdir_p
# echo "creating $dirpart/$file"
echo '# dummy' > "$dirpart/$file"
done
done
if test $am_rc -ne 0; then
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "Something went wrong bootstrapping makefile fragments
for automatic dependency tracking. Try re-running configure with the
'--disable-dependency-tracking' option to at least be able to build
the package (albeit without support for automatic dependency tracking).
See \`config.log' for more details" "$LINENO" 5; }
fi
{ am_dirpart=; unset am_dirpart;}
{ am_filepart=; unset am_filepart;}
{ am_mf=; unset am_mf;}
{ am_rc=; unset am_rc;}
rm -f conftest-deps.mk
}
;;
@@ -7591,7 +7402,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by qbittorrent $as_me v4.1.9.1, which was
This file was extended by qbittorrent $as_me v3.2.0alpha, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -7643,13 +7454,13 @@ Configuration commands:
$config_commands
Report bugs to <bugs.qbittorrent.org>.
qbittorrent home page: <https://www.qbittorrent.org/>."
qbittorrent home page: <http://www.qbittorrent.org/>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
qbittorrent config.status v4.1.9.1
qbittorrent config.status v3.2.0alpha
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
@@ -7757,7 +7568,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
#
# INIT-COMMANDS
#
AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"
AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
_ACEOF
@@ -8203,35 +8014,29 @@ $as_echo "$as_me: executing $ac_file commands" >&6;}
# Older Autoconf quotes --file arguments for eval, but not when files
# are listed without --file. Let's play safe and only enable the eval
# if we detect the quoting.
# TODO: see whether this extra hack can be removed once we start
# requiring Autoconf 2.70 or later.
case $CONFIG_FILES in #(
*\'*) :
eval set x "$CONFIG_FILES" ;; #(
*) :
set x $CONFIG_FILES ;; #(
*) :
;;
esac
case $CONFIG_FILES in
*\'*) eval set x "$CONFIG_FILES" ;;
*) set x $CONFIG_FILES ;;
esac
shift
# Used to flag and report bootstrapping failures.
am_rc=0
for am_mf
for mf
do
# Strip MF so we end up with the name of the file.
am_mf=`$as_echo "$am_mf" | sed -e 's/:.*$//'`
# Check whether this is an Automake generated Makefile which includes
# dependency-tracking related rules and includes.
# Grep'ing the whole file directly is not great: AIX grep has a line
mf=`echo "$mf" | sed -e 's/:.*$//'`
# Check whether this is an Automake generated Makefile or not.
# We used to match only the files named 'Makefile.in', but
# some people rename them; so instead we look at the file content.
# Grep'ing the first line is not enough: some people post-process
# each Makefile.in and add a new line on top of each file to say so.
# Grep'ing the whole file is not good either: AIX grep has a line
# limit of 2048, but all sed's we know have understand at least 4000.
sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \
|| continue
am_dirpart=`$as_dirname -- "$am_mf" ||
$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$am_mf" : 'X\(//\)[^/]' \| \
X"$am_mf" : 'X\(//\)$' \| \
X"$am_mf" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$am_mf" |
if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
dirpart=`$as_dirname -- "$mf" ||
$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$mf" : 'X\(//\)[^/]' \| \
X"$mf" : 'X\(//\)$' \| \
X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$mf" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
@@ -8249,48 +8054,53 @@ $as_echo X"$am_mf" |
q
}
s/.*/./; q'`
am_filepart=`$as_basename -- "$am_mf" ||
$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \
X"$am_mf" : 'X\(//\)$' \| \
X"$am_mf" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X/"$am_mf" |
sed '/^.*\/\([^/][^/]*\)\/*$/{
else
continue
fi
# Extract the definition of DEPDIR, am__include, and am__quote
# from the Makefile without running 'make'.
DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
test -z "$DEPDIR" && continue
am__include=`sed -n 's/^am__include = //p' < "$mf"`
test -z "$am__include" && continue
am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
# Find all dependency output files, they are included files with
# $(DEPDIR) in their names. We invoke sed twice because it is the
# simplest approach to changing $(DEPDIR) to its actual value in the
# expansion.
for file in `sed -n "
s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
# Make sure the directory exists.
test -f "$dirpart/$file" && continue
fdir=`$as_dirname -- "$file" ||
$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$file" : 'X\(//\)[^/]' \| \
X"$file" : 'X\(//\)$' \| \
X"$file" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$file" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\/\(\/\/\)$/{
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\/\(\/\).*/{
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'`
{ echo "$as_me:$LINENO: cd "$am_dirpart" \
&& sed -e '/# am--include-marker/d' "$am_filepart" \
| $MAKE -f - am--depfiles" >&5
(cd "$am_dirpart" \
&& sed -e '/# am--include-marker/d' "$am_filepart" \
| $MAKE -f - am--depfiles) >&5 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } || am_rc=$?
as_dir=$dirpart/$fdir; as_fn_mkdir_p
# echo "creating $dirpart/$file"
echo '# dummy' > "$dirpart/$file"
done
done
if test $am_rc -ne 0; then
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "Something went wrong bootstrapping makefile fragments
for automatic dependency tracking. Try re-running configure with the
'--disable-dependency-tracking' option to at least be able to build
the package (albeit without support for automatic dependency tracking).
See \`config.log' for more details" "$LINENO" 5; }
fi
{ am_dirpart=; unset am_dirpart;}
{ am_filepart=; unset am_filepart;}
{ am_mf=; unset am_mf;}
{ am_rc=; unset am_rc;}
rm -f conftest-deps.mk
}
;;

View File

@@ -1,4 +1,4 @@
AC_INIT([qbittorrent], [v4.1.9.1], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/])
AC_INIT([qbittorrent], [v3.2.0alpha], [bugs.qbittorrent.org], [], [http://www.qbittorrent.org/])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
AC_PROG_CC
@@ -8,9 +8,7 @@ AC_LANG(C++)
AC_CANONICAL_HOST
AM_INIT_AUTOMAKE
# use compiler from env variables if available
QBT_CC="$CC"
QBT_CXX="$CXX"
# Define --wth-* and --enable-* arguments
@@ -26,12 +24,6 @@ AC_ARG_ENABLE(debug,
[],
[enable_debug=no])
AC_ARG_ENABLE(stacktrace,
[AS_HELP_STRING([--enable-stacktrace],
[Enable stacktrace feature (default=auto)])],
[],
[enable_stacktrace=auto])
AC_ARG_ENABLE(gui,
[AS_HELP_STRING([--disable-gui],
[Disable the GUI for headless running. Disables QtDBus and the GeoIP Database.])],
@@ -88,23 +80,6 @@ AS_CASE(["x$enable_debug"],
[AC_MSG_RESULT([$enable_debug])
AC_MSG_ERROR([Unknown option "$enable_debug". Use either "yes" or "no".])])
AC_MSG_CHECKING([whether to enable the stacktrace feature])
AS_CASE(["x$enable_stacktrace"],
["xno"],
[AC_MSG_RESULT([no])
QBT_REMOVE_CONFIG="$QBT_REMOVE_CONFIG stacktrace"],
["xyes"],
[AC_MSG_RESULT([yes])
QBT_ADD_CONFIG="$QBT_ADD_CONFIG stacktrace"],
["xauto"],
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#include <execinfo.h>]])],
[AC_MSG_RESULT([yes])
QBT_ADD_CONFIG="$QBT_ADD_CONFIG stacktrace"],
[AC_MSG_RESULT([no])
QBT_REMOVE_CONFIG="$QBT_REMOVE_CONFIG stacktrace"])],
[AC_MSG_RESULT([$enable_stacktrace])
AC_MSG_ERROR([Unknown option "$enable_stacktrace". Use either "yes" or "no".])])
AC_MSG_CHECKING([whether to enable the GUI])
AS_CASE(["x$enable_gui"],
["xyes"],
@@ -164,21 +139,12 @@ AS_CASE(["x$enable_qt_dbus"],
AX_BOOST_BASE([1.35],
[AC_MSG_NOTICE([Boost CXXFLAGS: "$BOOST_CPPFLAGS"])
AC_MSG_NOTICE([Boost LDFLAGS: "$BOOST_LDFLAGS"])],
[AC_MSG_NOTICE([Boost CPPFLAGS: "$BOOST_CPPFLAGS"
Boost LDFLAGS: "$BOOST_LDFLAGS"])],
[AC_MSG_ERROR([Could not find Boost])])
CXXFLAGS="$BOOST_CPPFLAGS $CXXFLAGS"
CPPFLAGS="$BOOST_CPPFLAGS $CPPFLAGS"
LDFLAGS="$BOOST_LDFLAGS $LDFLAGS"
# add workaround for problematic boost version
# taken from ax_boost_base.m4
m4_define([DETECT_BOOST_VERSION_PROGRAM],
[AC_LANG_PROGRAM([[#include <boost/version.hpp>]],
[[(void) ((void)sizeof(char[1 - 2*!!((BOOST_VERSION) < ($1))]));]])])
AC_COMPILE_IFELSE([DETECT_BOOST_VERSION_PROGRAM(106000)], [],
[QBT_ADD_DEFINES="$QBT_ADD_DEFINES BOOST_NO_CXX11_RVALUE_REFERENCES"])
AX_BOOST_SYSTEM()
AC_MSG_NOTICE([Boost.System LIB: "$BOOST_SYSTEM_LIB"])
LIBS="$BOOST_SYSTEM_LIB $LIBS"
@@ -196,46 +162,14 @@ AS_CASE(["x$with_qtsingleapplication"],
PKG_CHECK_MODULES(libtorrent,
[libtorrent-rasterbar >= 1.0.6],
[CXXFLAGS="$libtorrent_CFLAGS $CXXFLAGS"
[CPPFLAGS="$libtorrent_CFLAGS $CPPFLAGS"
LIBS="$libtorrent_LIBS $LIBS"])
PKG_CHECK_MODULES(zlib,
[zlib >= 1.2.5.2],
[CXXFLAGS="$zlib_CFLAGS $CXXFLAGS"
[CPPFLAGS="$zlib_CFLAGS $CPPFLAGS"
LIBS="$zlib_LIBS $LIBS"])
# Check if already in >= C++11 mode because of the flags returned by one of the above packages
AC_MSG_CHECKING([if compiler is using C++11 or later mode])
AC_COMPILE_IFELSE([DETECT_CPP11_PROGRAM()],
[AC_MSG_RESULT([yes])
QBT_CXX11_FOUND="yes"],
[AC_MSG_RESULT([no])
QBT_CXX11_FOUND="no"])
# In case of no, check if the compiler can support at least C++11
# and if yes, enable it leaving a warning to the user
AS_IF([test "x$QBT_CXX11_FOUND" = "xno"],
[AC_MSG_CHECKING([if compiler supports C++11])
TMP_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS -std=c++11"
AC_COMPILE_IFELSE([DETECT_CPP11_PROGRAM()],
[AC_MSG_RESULT([yes])
AC_MSG_CHECKING([if C++11 is disabled by the set compiler flags])
# prepend the flag so it won't override conflicting user defined flags
CXXFLAGS="-std=c++11 $TMP_CXXFLAGS"
AC_COMPILE_IFELSE([DETECT_CPP11_PROGRAM()],
[AC_MSG_RESULT([no])
CXXFLAGS="$TMP_CXXFLAGS -std=c++11"
AC_MSG_WARN([C++11 mode is now force enabled.
Make sure you use the same C++ mode for qBittorrent and its dependencies.
To explicitly set qBittorrent to a later mode use CXXFLAGS.
Example: `CXXFLAGS="\$CXXFLAGS -std=c++14" ./configure`])],
[AC_MSG_RESULT([yes])
AC_MSG_ERROR([The compiler supports C++11 but the user or a dependency has explicitly enabled a lower mode.])])],
[AC_MSG_RESULT([no])
AC_MSG_ERROR([A compiler supporting C++11 is required.])])
])
# These are required because autoconf doesn't expand these **particular**
# vars automatically. And qmake cannot autoexpand them.
AX_DEFINE_DIR([EXPAND_PREFIX], [prefix])
@@ -256,26 +190,25 @@ extract() {
new_line='
'
# Convert " -" to "\n" if not between quotes and remove possible leading white spaces
string=$(echo " $*" | $SED -e "s: -:\\${new_line}:g" -e 's:"\(.*\)\n\(.*\)":\"\1 -\2":g' -e "s:'\(.*\)\n\(.*\)':\'\1 -\2':g" -e 's/^[[[:space:]]]*//')
string=$(echo " $*" | $SED -e "s: -:\\${new_line}:g" -e 's:"\(.*\)\n\(.*\)":\"\1 -\2":g' -e "s:'\(.*\)\n\(.*\)':\'\1 -\2':g" -e 's/^[[:space:]]*//')
SAVEIFS=$IFS
IFS=$(printf "\n\b")
for i in $string; do
case "$(echo "$i" | cut -c1)" in
'') ;;
D) QBT_CONF_DEFINES="$QBT_CONF_DEFINES $(echo $i | cut -c2-)";;
I) QBT_CONF_INCLUDES="$QBT_CONF_INCLUDES $(echo $i | cut -c2-)";;
*) QBT_CONF_EXTRA_CFLAGS="$QBT_CONF_EXTRA_CFLAGS -$i";;
D) QBT_CONF_DEFINES="$(echo $i | cut -c2-) $QBT_CONF_DEFINES";;
I) QBT_CONF_INCLUDES="$(echo $i | cut -c2-) $QBT_CONF_INCLUDES";;
*) QBT_CONF_EXTRA_CFLAGS="-$i $QBT_CONF_EXTRA_CFLAGS";;
esac
done
IFS=$SAVEIFS
}
extract "$CFLAGS $CXXFLAGS"
extract $CPPFLAGS
QBT_ADD_DEFINES="$QBT_ADD_DEFINES $QBT_CONF_DEFINES"
QBT_CONF_EXTRA_CFLAGS="$QBT_CONF_EXTRA_CFLAGS $CXXFLAGS"
# Substitute the values of these vars in conf.pri.in
AC_SUBST(QBT_CC)
AC_SUBST(QBT_CXX)
AC_SUBST(QBT_CONF_INCLUDES)
AC_SUBST(QBT_CONF_EXTRA_CFLAGS)
AC_SUBST(QBT_ADD_CONFIG)

2
dist/CMakeLists.txt vendored
View File

@@ -1,5 +1,3 @@
find_package(Qt5Widgets ${requiredQtVersion}) # to conditionally install desktop-related files
if (APPLE)
add_subdirectory(mac)
else (APPLE)

22
dist/mac/Info.plist vendored
View File

@@ -2,10 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>qBittorrent</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
@@ -25,10 +21,6 @@
<array>
<string>org.bittorrent.torrent</string>
</array>
<key>NSExportableTypes</key>
<array>
<string>org.bittorrent.torrent</string>
</array>
<key>LSIsAppleDefaultForType</key>
<true/>
</dict>
@@ -36,8 +28,6 @@
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>CFBundleURLSchemes</key>
<array>
<string>magnet</string>
@@ -55,19 +45,21 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>4.1.9</string>
<string>4.0.3</string>
<key>CFBundleSignature</key>
<string>qBit</string>
<key>CFBundleExecutable</key>
<string>@EXECUTABLE@</string>
<key>CFBundleIdentifier</key>
<string>org.qbittorrent.qBittorrent</string>
<key>LSMinimumSystemVersion</key>
<string>${MACOSX_DEPLOYMENT_TARGET}.0</string>
<string>org.qbittorrent</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSHighResolutionCapable</key>
<string>True</string>
<key>NSAppleScriptEnabled</key>
<string>YES</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2006-2019 The qBittorrent project</string>
<string>Copyright © 2006-2017 The qBittorrent project</string>
<key>UTExportedTypeDeclarations</key>
<array>
<dict>

Binary file not shown.

View File

@@ -1,42 +1,36 @@
if (NOT Qt5Widgets_FOUND)
feature_option(SYSTEMD "Install systemd service file (headless only)" OFF)
if (SYSTEMD)
if (NOT Systemd_SERVICES_INSTALL_DIR)
find_package(Systemd)
if (NOT Systemd_FOUND)
message(FATAL_ERROR "Could not locate systemd services install dir."
" Either pass -DSystemd_SERVICES_INSTALL_DIR=/path/to/systemd/services option or install systemd pkg-config")
endif(NOT Systemd_FOUND)
endif(NOT Systemd_SERVICES_INSTALL_DIR)
if (SYSTEMD)
find_package(Systemd)
if (SYSTEMD_FOUND)
set(EXPAND_BINDIR ${CMAKE_INSTALL_FULL_BINDIR})
configure_file(systemd/qbittorrent-nox@.service.in ${CMAKE_CURRENT_BINARY_DIR}/qbittorrent-nox@.service @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qbittorrent-nox@.service
DESTINATION ${Systemd_SERVICES_INSTALL_DIR}
DESTINATION ${SYSTEMD_SERVICES_INSTALL_DIR}
COMPONENT data)
endif(SYSTEMD)
endif()
endif(SYSTEMD_FOUND)
endif(SYSTEMD)
if (Qt5Widgets_FOUND)
if (GUI)
list(APPEND MAN_FILES ${qBittorrent_SOURCE_DIR}/doc/qbittorrent.1)
else (Qt5Widgets_FOUND)
else (GUI)
list(APPEND MAN_FILES ${qBittorrent_SOURCE_DIR}/doc/qbittorrent-nox.1)
endif (Qt5Widgets_FOUND)
endif (GUI)
install(FILES ${MAN_FILES}
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1
COMPONENT doc)
if (Qt5Widgets_FOUND)
if (GUI)
install(DIRECTORY menuicons/
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor
FILES_MATCHING PATTERN "*.png")
install(FILES org.qbittorrent.qBittorrent.desktop
install(FILES ${qBittorrent_SOURCE_DIR}/src/icons/qbittorrent.desktop
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications/
COMPONENT data)
install(FILES org.qbittorrent.qBittorrent.appdata.xml
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/metainfo/
install(FILES qbittorrent.appdata.xml
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/appdata/
COMPONENT data)
install(FILES

View File

@@ -1,75 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2014 sledgehammer999 <sledgehammer999@qbittorrent.org> -->
<component type="desktop">
<id>org.qbittorrent.qBittorrent</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-2.0 and OpenSSL</project_license>
<name>qBittorrent</name>
<summary>An open-source Bittorrent client</summary>
<description>
<p>
The qBittorrent project aims to provide an open-source software alternative to µTorrent.
Additionally, qBittorrent runs and provides the same features on all major platforms (FreeBSD, Linux, macOS, OS/2, Windows).
qBittorrent is based on the Qt toolkit and libtorrent-rasterbar library.
</p>
<ul>
<li>Polished µTorrent-like User Interface</li>
<li>
Well-integrated and extensible Search Engine
<ul>
<li>Simultaneous search in many Torrent search sites</li>
<li>Category-specific search requests (e.g. Books, Music, Software)</li>
</ul>
</li>
<li>RSS feed support with advanced download filters (incl. regex)</li>
<li>
Many Bittorrent extensions supported:
<ul>
<li>Magnet links</li>
<li>Distributed hash table (DHT), peer exchange protocol (PEX), local peer discovery (LSD)</li>
<li>Private torrents</li>
<li>Encrypted connections</li>
<li>and many more...</li>
</ul>
</li>
<li>Remote control through Web user interface, written with AJAX</li>
<li>Sequential downloading (Download in order)</li>
<li>
Advanced control over torrents, trackers and peers
<ul>
<li>Torrents queueing and prioritizing</li>
<li>Torrent content selection and prioritizing</li>
</ul>
</li>
<li>Bandwidth scheduler</li>
<li>Torrent creation tool</li>
<li>IP Filtering (eMule &amp; PeerGuardian format compatible)</li>
<li>IPv6 compliant</li>
<li>UPnP / NAT-PMP port forwarding support</li>
<li>Available on all platforms: Windows, Linux, macOS, FreeBSD, OS/2</li>
<li>Available in ~70 languages</li>
</ul>
</description>
<launchable type="desktop-id">org.qbittorrent.qBittorrent.desktop</launchable>
<screenshots>
<screenshot type="default">
<image height="675" width="1200">https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_01.png</image>
</screenshot>
<screenshot>
<image height="675" width="1200">https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_02.png</image>
</screenshot>
<screenshot>
<image height="675" width="1200">https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_03.png</image>
</screenshot>
<screenshot>
<image height="675" width="1200">https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_04.png</image>
</screenshot>
</screenshots>
<update_contact>sledgehammer999@qbittorrent.org</update_contact>
<developer_name>The qBittorrent Project</developer_name>
<url type="homepage">https://www.qbittorrent.org/</url>
<url type="bugtracker">http://bugs.qbittorrent.org/</url>
<url type="donation">https://www.qbittorrent.org/donate</url>
<url type="help">http://forum.qbittorrent.org/</url>
<url type="translate">https://github.com/qbittorrent/qBittorrent/wiki/How-to-translate-qBittorrent</url>
</component>

66
dist/unix/qbittorrent.appdata.xml vendored Normal file
View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2014 sledgehammer999 <sledgehammer999@qbittorrent.org> -->
<component type="desktop">
<id>qbittorrent.desktop</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-2.0 and OpenSSL</project_license>
<name>qBittorrent</name>
<summary>A Bittorrent Client</summary>
<description>
<p>
Aiming to be a good alternative to all other bittorrent clients out
there, qBittorrent is fast, stable and provides unicode support as well
as many other features. Additionally, qBittorrent runs and provides those
same features on all major platforms (Linux, Mac OS X, Windows, FreeBSD).
</p>
<p>
It is programmed in C++ / Qt and uses libtorrent (sometimes called
libtorrent-rasterbar) by Arvid Norberg. GeoLite data, created by MaxMind,
are included in qBittorrent. Its features include:
</p>
<ul>
<li>Polished µTorrent-like User Interface</li>
<li>Well-integrated and extensible Search Engine</li>
<li>All Bittorrent extensions (DHT, Peer Exchange, Full encryption, Magnet/BitComet URIs, ...)</li>
<li>Remote control through a Web user interface</li>
<li>Advanced control over trackers, peers and torrents</li>
<li>UPnP / NAT-PMP port forwarding support</li>
<li>Available in ~25 languages (Unicode support)</li>
<li>Torrent creation tool</li>
<li>Advanced RSS support with download filters (inc. regex)</li>
<li>Bandwidth scheduler</li>
<li>IP Filtering (eMule and PeerGuardian compatible)</li>
<li>IPv6 compliant</li>
<li>Sequential downloading (aka "Download in order")</li>
</ul>
</description>
<screenshots>
<screenshot type="default">
<image height="675" width="1200">
https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_01.png
</image>
</screenshot>
<screenshot>
<image height="675" width="1200">
https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_02.png
</image>
</screenshot>
<screenshot>
<image height="675" width="1200">
https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_03.png
</image>
</screenshot>
<screenshot>
<image height="675" width="1200">
https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_04.png
</image>
</screenshot>
</screenshots>
<url type="homepage">http://www.qbittorrent.org/</url>
<update_contact>sledgehammer999@qbittorrent.org</update_contact>
<developer_name>The qBittorrent Project</developer_name>
<url type="bugtracker">http://bugs.qbittorrent.org/</url>
<url type="donation">https://www.qbittorrent.org/donate</url>
<url type="help">http://forum.qbittorrent.org/</url>
<url type="translate">https://github.com/qbittorrent/qBittorrent/wiki/How-to-translate-qBittorrent</url>
</component>

View File

@@ -86,7 +86,7 @@ Section $(inst_qbt_req) ;"qBittorrent (required)"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qBittorrent" "UninstallString" '"$INSTDIR\uninst.exe"'
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qBittorrent" "DisplayIcon" '"$INSTDIR\qbittorrent.exe",0'
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qBittorrent" "Publisher" "The qBittorrent project"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qBittorrent" "URLInfoAbout" "https://www.qbittorrent.org"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qBittorrent" "URLInfoAbout" "http://www.qbittorrent.org"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qBittorrent" "DisplayVersion" "${PROG_VERSION}"
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qBittorrent" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\qBittorrent" "NoRepair" 1

View File

@@ -27,7 +27,7 @@ XPStyle on
!define CSIDL_LOCALAPPDATA '0x1C' ;Local Application Data path
; Program specific
!define PROG_VERSION "4.1.9.1"
!define PROG_VERSION "4.0.3"
!define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun
@@ -50,11 +50,11 @@ XPStyle on
;Installer Version Information
VIAddVersionKey "ProductName" "qBittorrent"
VIAddVersionKey "CompanyName" "The qBittorrent project"
VIAddVersionKey "LegalCopyright" "Copyright ©2006-2019 The qBittorrent project"
VIAddVersionKey "LegalCopyright" "Copyright ©2006-2017 The qBittorrent project"
VIAddVersionKey "FileDescription" "qBittorrent - A Bittorrent Client"
VIAddVersionKey "FileVersion" "${PROG_VERSION}"
VIProductVersion "${PROG_VERSION}.1"
VIProductVersion "${PROG_VERSION}.0"
; The default installation directory. It changes depending if we install in the 64bit dir or not.
; A caveat of this is if a user has installed a 32bit version and then runs the 64bit installer

View File

@@ -33,7 +33,7 @@
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 47
#serial 42
# example boost program (need to pass version)
m4_define([_AX_BOOST_BASE_PROGRAM],
@@ -113,8 +113,7 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[
dnl are found, e.g. when only header-only libraries are installed!
AS_CASE([${host_cpu}],
[x86_64],[libsubdirs="lib64 libx32 lib lib64"],
[mips*64*],[libsubdirs="lib64 lib32 lib lib64"],
[ppc64|powerpc64|s390x|sparc64|aarch64|ppc64le|powerpc64le|riscv64],[libsubdirs="lib64 lib lib64"],
[ppc64|s390x|sparc64|aarch64|ppc64le],[libsubdirs="lib64 lib lib64"],
[libsubdirs="lib"]
)

View File

@@ -31,7 +31,7 @@
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 20
#serial 19
AC_DEFUN([AX_BOOST_SYSTEM],
[
@@ -108,7 +108,7 @@ AC_DEFUN([AX_BOOST_SYSTEM],
fi
if test "x$ax_lib" = "x"; then
AC_MSG_ERROR(Could not find a version of the Boost::System library!)
AC_MSG_ERROR(Could not find a version of the library!)
fi
if test "x$link_system" = "xno"; then
AC_MSG_ERROR(Could not link against $ax_lib !)

View File

@@ -36,16 +36,3 @@ AC_DEFUN([FIND_QTDBUS],
[AC_MSG_RESULT([not found])
HAVE_QTDBUS=[false]])
])
# DETECT_CPP11_PROGRAM()
# Detects if at least C++11 mode is enabled.
# --------------------------------------
AC_DEFUN([DETECT_CPP11_PROGRAM],
[AC_LANG_PROGRAM([[
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201103L
#error "This is not a C++11 compiler"
#endif]],
[[]])
])

View File

@@ -3,6 +3,7 @@ TEMPLATE = subdirs
SUBDIRS += src
include(version.pri)
include(qm_gen.pri)
# Make target to create release tarball. Use 'make tarball'
tarball.commands += rm -fR ../$${PROJECT_NAME}-$${PROJECT_VERSION}/ &&
@@ -16,11 +17,3 @@ tarball.commands += xz -f $${PROJECT_NAME}-$${PROJECT_VERSION}.tar &&
tarball.commands += rm -fR $${PROJECT_NAME}-$${PROJECT_VERSION}
QMAKE_EXTRA_TARGETS += tarball
# Translations included here (at top level) is to avoid regenerating the .qm files
# every time when src.pro is processed
include(src/lang/lang.pri)
# For Qt Creator beautifier
DISTFILES += \
uncrustify.cfg

21
qm_gen.pri Normal file
View File

@@ -0,0 +1,21 @@
TS_IN = $$fromfile(src/src.pro,TRANSLATIONS)
TS_IN_NOEXT = $$replace(TS_IN,".ts","")
isEmpty(QMAKE_LRELEASE) {
win32:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]\\lrelease.exe
else:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]/lrelease
unix {
equals(QT_MAJOR_VERSION, 5) {
!exists($$QMAKE_LRELEASE) { QMAKE_LRELEASE = lrelease-qt5 }
}
} else {
!exists($$QMAKE_LRELEASE) { QMAKE_LRELEASE = lrelease }
}
}
message("Building translations")
for(L,TS_IN_NOEXT) {
message("Processing $${L}")
system("$$QMAKE_LRELEASE -silent src/$${L}.ts -qm src/$${L}.qm")
!exists("src/$${L}.qm"):error("Building translations failed, cannot continue")
}

View File

@@ -1,53 +1,40 @@
set(CMAKE_CXX_STANDARD_REQUIRED True)
# If C++14 is available, use it as libtorent ABI depends on 11/14 version
if (cxx_std_14 IN_LIST CMAKE_CXX_COMPILE_FEATURES)
message(STATUS "Building in C++14 mode")
set(CMAKE_CXX_STANDARD "14")
else()
message(STATUS "Building in C++11 mode")
set(CMAKE_CXX_STANDARD "11")
endif()
set(CMAKE_CXX_STANDARD "11")
add_definitions(-DBOOST_NO_CXX11_RVALUE_REFERENCES)
include(MacroQbtCompilerSettings)
qbt_set_compiler_options()
include(MacroLinkQtComponents)
include(QbtTargetSources)
find_package(Boost ${requiredBoostVersion} REQUIRED)
find_package(LibtorrentRasterbar REQUIRED)
if (Boost_VERSION VERSION_LESS 106000)
add_definitions(-DBOOST_NO_CXX11_RVALUE_REFERENCES)
endif()
# Qt
list(APPEND QBT_QT_COMPONENTS Core Network Xml)
if (GUI)
list (APPEND QBT_QT_COMPONENTS Gui Svg Widgets)
if (WIN32)
list (APPEND QBT_QT_COMPONENTS WinExtras)
endif(WIN32)
if (APPLE)
list (APPEND QBT_GUI_OPTIONAL_LINK_LIBRARIES objc)
list (APPEND QBT_QT_COMPONENTS MacExtras)
endif (APPLE)
endif (GUI)
if (DBUS)
list (APPEND QBT_QT_COMPONENTS DBus)
endif (DBUS)
find_package(Qt5 5.5.1 COMPONENTS ${QBT_QT_COMPONENTS} REQUIRED)
find_package(Qt5 ${requiredQtVersion} REQUIRED COMPONENTS Core Network Xml LinguistTools)
find_package(Qt5Widgets ${requiredQtVersion})
if (Qt5Widgets_FOUND)
find_package(Qt5DBus ${requiredQtVersion})
else()
add_definitions(-DDISABLE_GUI)
endif()
set_package_properties(Qt5Widgets PROPERTIES
DESCRIPTION "Set of components for creating classic desktop-style UIs for the Qt5 framework"
PURPOSE "Enables qBittorrent GUI. Unneeded for headless configuration."
TYPE OPTIONAL
)
set_package_properties(Qt5DBus PROPERTIES
DESCRIPTION "Qt5 module for inter-process communication over the D-Bus protocol"
PURPOSE "Enables communication with other system components (e.g. notification service) via D-Bus. "
TYPE RECOMMENDED
)
if (GUI AND APPLE)
# Fix MOC inability to detect macOS. This seems to only affect cmake.
# Relevant issue: https://bugreports.qt.io/browse/QTBUG-58325
set(CMAKE_AUTOMOC_MOC_OPTIONS ${CMAKE_AUTOMOC_MOC_OPTIONS} -DQ_OS_MAC)
endif ()
set(CMAKE_AUTOMOC True)
list(APPEND CMAKE_AUTORCC_OPTIONS -compress 9 -threshold 5)
if (APPLE)
# Workaround CMake bug (autogen does not pass required parameters to moc)
# Relevant issue: https://gitlab.kitware.com/cmake/cmake/issues/18041
list(APPEND CMAKE_AUTOMOC_MOC_OPTIONS -DQ_OS_MAC -DQ_OS_DARWIN)
endif ()
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
@@ -56,34 +43,56 @@ add_definitions(-DQT_NO_CAST_TO_ASCII)
# Efficient construction for QString & QByteArray (Qt >= 4.8)
add_definitions(-DQT_USE_QSTRINGBUILDER)
if (CMAKE_BUILD_TYPE MATCHES "Debug")
if (NOT GUI)
add_definitions(-DDISABLE_GUI -DDISABLE_COUNTRIES_RESOLUTION)
endif (NOT GUI)
if (NOT WEBUI)
add_definitions(-DDISABLE_WEBUI)
endif (NOT WEBUI)
if (STACKTRACE_WIN)
add_definitions(-DSTACKTRACE_WIN)
endif(STACKTRACE_WIN)
# nogui {
# TARGET = qbittorrent-nox
# } else {
# CONFIG(static) {
# DEFINES += QBT_STATIC_QT
# QTPLUGIN += qico
# }
# TARGET = qbittorrent
# }
if (UNIX AND NOT APPLE)
add_compile_options(-Wformat -Wformat-security)
endif ()
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
message(STATUS "Project is built in DEBUG mode.")
else()
else (CMAKE_BUILD_TYPE STREQUAL "Debug")
message(STATUS "Project is built in RELEASE mode.")
message(STATUS "Disabling debug output.")
add_definitions(-DQT_NO_DEBUG_OUTPUT)
endif()
endif (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(QBT_USE_GUI ${GUI})
set(QBT_USE_WEBUI ${WEBUI})
configure_file(config.h.cmakein ${CMAKE_CURRENT_BINARY_DIR}/config.h)
find_package(QtSingleApplication)
set_package_properties(QtSingleApplication PROPERTIES
URL "https://code.qt.io/cgit/qt-solutions/qt-solutions.git/"
DESCRIPTION "Qt library to start applications only once per user"
TYPE RECOMMENDED
PURPOSE "Use the system qtsingleapplication library or shipped one otherwise"
)
if (NOT QtSingleApplication_FOUND)
if (SYSTEM_QTSINGLEAPPLICATION)
find_package(QtSingleApplication REQUIRED)
else (SYSTEM_QTSINGLEAPPLICATION)
add_subdirectory(app/qtsingleapplication)
endif ()
endif (SYSTEM_QTSINGLEAPPLICATION)
add_subdirectory(app)
add_subdirectory(base)
if (Qt5Widgets_FOUND)
if (GUI)
add_subdirectory(gui)
endif ()
endif (GUI)
if (WEBUI)
add_subdirectory(webui)

View File

@@ -1,41 +1,43 @@
add_executable(qBittorrent
project(qbt_executable)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
set(QBT_APP_HEADERS
application.h
cmdoptions.h
filelogger.h
upgrade.h
)
set(QBT_APP_SOURCES
application.cpp
cmdoptions.cpp
filelogger.cpp
main.cpp
)
target_include_directories(qBittorrent PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(qBittorrent
PRIVATE
qbt_base
)
set_target_properties(qBittorrent
PROPERTIES
AUTOUIC True
AUTORCC True
MACOSX_BUNDLE True
)
# translations
include(QbtTranslations)
file(GLOB QBT_TS_FILES ../lang/*.ts)
qbt_add_translations(qBittorrent QRC_FILE "../lang/lang.qrc" TS_FILES ${QBT_TS_FILES})
get_filename_component(QBT_QM_FILES_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/../lang" ABSOLUTE)
set_source_files_properties(${QBT_TS_FILES} PROPERTIES OUTPUT_LOCATION "${QBT_QM_FILES_BINARY_DIR}")
if (WEBUI)
file(GLOB QBT_WEBUI_TS_FILES ../webui/www/translations/*.ts)
qbt_add_translations(qBittorrent QRC_FILE "../webui/www/translations/webui_translations.qrc" TS_FILES ${QBT_WEBUI_TS_FILES})
endif()
find_package(Qt5 COMPONENTS LinguistTools REQUIRED)
qt5_add_translation(QBT_QM_FILES ${QBT_TS_FILES})
get_filename_component(_lang_qrc_src "${CMAKE_CURRENT_SOURCE_DIR}/../lang.qrc" ABSOLUTE)
get_filename_component(_lang_qrc_dst "${CMAKE_CURRENT_BINARY_DIR}/../lang.qrc" ABSOLUTE)
get_filename_component(_lang_qrc_dst_dir "${CMAKE_CURRENT_BINARY_DIR}/../" ABSOLUTE)
message(STATUS "copying ${_lang_qrc_src} -> ${_lang_qrc_dst}")
file(COPY ${_lang_qrc_src} DESTINATION ${_lang_qrc_dst_dir})
set_source_files_properties("${_lang_qrc_dst}" PROPERTIES GENERATED True)
foreach(qm_file ${QBT_QM_FILES})
set_source_files_properties("${_lang_qrc_dst}" PROPERTIES OBJECT_DEPENDS ${qm_file})
endforeach()
set(QBT_APP_RESOURCES
../icons/icons.qrc
../searchengine/searchengine.qrc
../icons.qrc
../searchengine.qrc
"${_lang_qrc_dst}"
)
# With AUTORCC rcc is ran by cmake before language files are generated,
@@ -44,41 +46,51 @@ qt5_add_resources(QBT_APP_RESOURCE_SOURCE ${QBT_APP_RESOURCES})
if (WIN32)
if (MINGW)
target_sources(qBittorrent PRIVATE ../qbittorrent_mingw.rc)
list (APPEND QBT_APP_SOURCES ../qbittorrent_mingw.rc)
else (MINGW)
target_sources(qBittorrent PRIVATE ../qbittorrent.rc)
list (APPEND QBT_APP_SOURCES ../qbittorrent.rc)
endif (MINGW)
target_sources(qBittorrent PRIVATE ../qbittorrent.exe.manifest)
list(APPEND QBT_APP_SOURCES ../qbittorrent.exe.manifest)
endif (WIN32)
if (STACKTRACE)
if (UNIX)
target_sources(qBittorrent PRIVATE stacktrace.h)
else (UNIX)
target_sources(qBittorrent PRIVATE stacktrace_win.h)
if (Qt5Widgets_FOUND)
target_sources(qBittorrent PRIVATE stacktracedialog.h)
endif (Qt5Widgets_FOUND)
endif (UNIX)
endif (STACKTRACE)
if (UNIX)
list(APPEND QBT_APP_HEADERS stacktrace.h)
endif (UNIX)
if (STACKTRACE_WIN)
list(APPEND QBT_APP_HEADERS stacktrace_win.h)
if (GUI)
list(APPEND QBT_APP_HEADERS stacktrace_win_dlg.h)
endif (GUI)
endif (STACKTRACE_WIN)
if (Qt5Widgets_FOUND)
target_link_libraries(qBittorrent PRIVATE qbt_searchengine qbt_gui)
set_target_properties(qBittorrent
PROPERTIES
OUTPUT_NAME qbittorrent
WIN32_EXECUTABLE True
# usesystemqtsingleapplication {
# nogui {
# CONFIG += qtsinglecoreapplication
# } else {
# CONFIG += qtsingleapplication
# }
# } else {
# nogui {
# include(qtsingleapplication/qtsinglecoreapplication.pri)
# } else {
# include(qtsingleapplication/qtsingleapplication.pri)
# }
# }
# upgrade code
list(APPEND QBT_APP_HEADERS upgrade.h)
list(APPEND QBT_TARGET_LIBRARIES qbt_base)
if (GUI)
list(APPEND QBT_TARGET_LIBRARIES qbt_searchengine qbt_gui)
include_directories(../gui
${CMAKE_CURRENT_BINARY_DIR}/../gui
)
else(Qt5Widgets_FOUND)
set_target_properties(qBittorrent
PROPERTIES
OUTPUT_NAME qbittorrent-nox
)
endif (Qt5Widgets_FOUND)
endif (GUI)
if (WEBUI)
target_link_libraries(qBittorrent PRIVATE qbt_webui)
list(APPEND QBT_TARGET_LIBRARIES qbt_webui)
endif (WEBUI)
# we have to include resources into the bundle
@@ -130,11 +142,30 @@ if (APPLE)
PROPERTIES MACOSX_PACKAGE_LOCATION translations)
endif (APPLE)
target_sources(qBittorrent PRIVATE ${QBT_QM_FILES} ${QBT_APP_RESOURCE_SOURCE})
add_executable(qBittorrent ${QBT_APP_HEADERS} ${QBT_APP_SOURCES} ${QBT_QM_FILES} ${QBT_APP_RESOURCE_SOURCE})
if (GUI)
set_target_properties(qBittorrent
PROPERTIES
OUTPUT_NAME qbittorrent
WIN32_EXECUTABLE True
)
else (GUI)
set_target_properties(qBittorrent
PROPERTIES
OUTPUT_NAME qbittorrent-nox
)
endif (GUI)
set_target_properties(qBittorrent
PROPERTIES
AUTOUIC True
AUTORCC True
MACOSX_BUNDLE True
)
get_target_property(QBT_EXECUTABLE_NAME qBittorrent OUTPUT_NAME)
target_link_libraries(qBittorrent PRIVATE ${QBT_TARGET_LIBRARIES} QtSingleApplication::QtSingleApplication)
target_link_libraries(qBittorrent ${QBT_TARGET_LIBRARIES} QtSingleApplication::QtSingleApplication)
if (APPLE)
set(qbt_BUNDLE_NAME ${QBT_EXECUTABLE_NAME})
@@ -155,7 +186,6 @@ install(TARGETS qBittorrent
BUNDLE DESTINATION .
COMPONENT runtime)
if (Qt5Widgets_FOUND AND APPLE)
find_package(Qt5Svg REQUIRED)
if (GUI AND APPLE)
include(bundle)
endif (Qt5Widgets_FOUND AND APPLE)
endif (GUI AND APPLE)

View File

@@ -25,16 +25,12 @@ SOURCES += \
$$PWD/filelogger.cpp \
$$PWD/main.cpp
stacktrace {
unix {
HEADERS += $$PWD/stacktrace.h
}
else {
HEADERS += $$PWD/stacktrace_win.h
!nogui {
HEADERS += $$PWD/stacktracedialog.h
FORMS += $$PWD/stacktracedialog.ui
}
unix: HEADERS += $$PWD/stacktrace.h
strace_win {
HEADERS += $$PWD/stacktrace_win.h
!nogui {
HEADERS += $$PWD/stacktrace_win_dlg.h
FORMS += $$PWD/stacktrace_win_dlg.ui
}
}

View File

@@ -27,89 +27,77 @@
* exception statement from your version.
*/
#include "application.h"
#include <algorithm>
#include <QAtomicInt>
#include <QDebug>
#include <QLibraryInfo>
#include <QFileInfo>
#include <QLocale>
#include <QProcess>
#include <QLibraryInfo>
#include <QSysInfo>
#ifdef Q_OS_WIN
#include <memory>
#include <Shellapi.h>
#endif
#include <QProcess>
#include <QAtomicInt>
#ifndef DISABLE_GUI
#include <QMessageBox>
#include "gui/guiiconprovider.h"
#ifdef Q_OS_WIN
#include <QSessionManager>
#include <windows.h>
#include <QSharedMemory>
#include <QSessionManager>
#endif // Q_OS_WIN
#ifdef Q_OS_MAC
#include <QFileOpenEvent>
#include <QFont>
#include <QUrl>
#endif // Q_OS_MAC
#include "addnewtorrentdialog.h"
#include "gui/guiiconprovider.h"
#include "mainwindow.h"
#include "shutdownconfirmdialog.h"
#include "addnewtorrentdialog.h"
#include "shutdownconfirmdlg.h"
#else // DISABLE_GUI
#include <cstdio>
#include <iostream>
#endif // DISABLE_GUI
#include "base/bittorrent/session.h"
#include "base/bittorrent/torrenthandle.h"
#include "base/exceptions.h"
#include "base/iconprovider.h"
#include "base/logger.h"
#include "base/net/downloadmanager.h"
#include "base/net/geoipmanager.h"
#include "base/net/proxyconfigurationmanager.h"
#include "base/net/smtp.h"
#include "base/preferences.h"
#include "base/profile.h"
#include "base/rss/rss_autodownloader.h"
#include "base/rss/rss_session.h"
#include "base/scanfoldersmodel.h"
#include "base/search/searchpluginmanager.h"
#include "base/settingsstorage.h"
#include "base/utils/fs.h"
#include "base/utils/misc.h"
#include "base/utils/string.h"
#include "filelogger.h"
#ifndef DISABLE_WEBUI
#include "webui/webui.h"
#endif
#include "application.h"
#include "filelogger.h"
#include "base/logger.h"
#include "base/preferences.h"
#include "base/settingsstorage.h"
#include "base/profile.h"
#include "base/utils/fs.h"
#include "base/utils/misc.h"
#include "base/iconprovider.h"
#include "base/scanfoldersmodel.h"
#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"
#include "base/rss/rss_autodownloader.h"
#include "base/rss/rss_session.h"
namespace
{
#define SETTINGS_KEY(name) "Application/" name
// FileLogger properties keys
#define FILELOGGER_SETTINGS_KEY(name) QStringLiteral(SETTINGS_KEY("FileLogger/") name)
#define FILELOGGER_SETTINGS_KEY(name) SETTINGS_KEY("FileLogger/") name
const QString KEY_FILELOGGER_ENABLED = FILELOGGER_SETTINGS_KEY("Enabled");
const QString KEY_FILELOGGER_PATH = FILELOGGER_SETTINGS_KEY("Path");
const QString KEY_FILELOGGER_BACKUP = FILELOGGER_SETTINGS_KEY("Backup");
const QString KEY_FILELOGGER_DELETEOLD = FILELOGGER_SETTINGS_KEY("DeleteOld");
const QString KEY_FILELOGGER_MAXSIZEBYTES = FILELOGGER_SETTINGS_KEY("MaxSizeBytes");
const QString KEY_FILELOGGER_MAXSIZE = FILELOGGER_SETTINGS_KEY("MaxSize");
const QString KEY_FILELOGGER_AGE = FILELOGGER_SETTINGS_KEY("Age");
const QString KEY_FILELOGGER_AGETYPE = FILELOGGER_SETTINGS_KEY("AgeType");
// just a shortcut
//just a shortcut
inline SettingsStorage *settings() { return SettingsStorage::instance(); }
const QString LOG_FOLDER = QStringLiteral("logs");
const QChar PARAMS_SEPARATOR = '|';
const QString LOG_FOLDER("logs");
const char PARAMS_SEPARATOR[] = "|";
const QString DEFAULT_PORTABLE_MODE_PROFILE_DIR = QStringLiteral("profile");
const int MIN_FILELOG_SIZE = 1024; // 1KiB
const int MAX_FILELOG_SIZE = 1000 * 1024 * 1024; // 1000MiB
const int DEFAULT_FILELOG_SIZE = 65 * 1024; // 65KiB
const QString DEFAULT_PORTABLE_MODE_PROFILE_DIR = QLatin1String("profile");
}
Application::Application(const QString &id, int &argc, char **argv)
@@ -124,7 +112,6 @@ Application::Application(const QString &id, int &argc, char **argv)
qRegisterMetaType<Log::Msg>("Log::Msg");
setApplicationName("qBittorrent");
setOrganizationDomain("qbittorrent.org");
validateCommandLineParameters();
QString profileDir = m_commandLineArgs.portableMode
@@ -141,22 +128,20 @@ Application::Application(const QString &id, int &argc, char **argv)
if (m_commandLineArgs.webUiPort > 0) // it will be -1 when user did not set any value
Preferences::instance()->setWebUiPort(m_commandLineArgs.webUiPort);
setApplicationName("qBittorrent");
initializeTranslation();
#if !defined(DISABLE_GUI)
setAttribute(Qt::AA_UseHighDpiPixmaps, true); // opt-in to the high DPI pixmap support
setQuitOnLastWindowClosed(false);
#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
setDesktopFileName("org.qbittorrent.qBittorrent");
#endif
#endif
#if defined(Q_OS_WIN) && !defined(DISABLE_GUI)
connect(this, &QGuiApplication::commitDataRequest, this, &Application::shutdownCleanup, Qt::DirectConnection);
connect(this, SIGNAL(commitDataRequest(QSessionManager &)), this, SLOT(shutdownCleanup(QSessionManager &)), Qt::DirectConnection);
#endif
connect(this, &Application::messageReceived, this, &Application::processMessage);
connect(this, &QCoreApplication::aboutToQuit, this, &Application::cleanup);
connect(this, SIGNAL(messageReceived(const QString &)), SLOT(processMessage(const QString &)));
connect(this, SIGNAL(aboutToQuit()), SLOT(cleanup()));
if (isFileLoggerEnabled())
m_fileLogger = new FileLogger(fileLoggerPath(), isFileLoggerBackup(), fileLoggerMaxSize(), isFileLoggerDeleteOld(), fileLoggerAge(), static_cast<FileLogger::FileLogAgeType>(fileLoggerAgeType()));
@@ -236,22 +221,29 @@ void Application::setFileLoggerDeleteOld(bool value)
int Application::fileLoggerMaxSize() const
{
int val = settings()->loadValue(KEY_FILELOGGER_MAXSIZEBYTES, DEFAULT_FILELOG_SIZE).toInt();
return std::min(std::max(val, MIN_FILELOG_SIZE), MAX_FILELOG_SIZE);
int val = settings()->loadValue(KEY_FILELOGGER_MAXSIZE, 10).toInt();
if (val < 1)
return 1;
if (val > 1000)
return 1000;
return val;
}
void Application::setFileLoggerMaxSize(const int bytes)
void Application::setFileLoggerMaxSize(const int value)
{
int clampedValue = std::min(std::max(bytes, MIN_FILELOG_SIZE), MAX_FILELOG_SIZE);
if (m_fileLogger)
m_fileLogger->setMaxSize(clampedValue);
settings()->storeValue(KEY_FILELOGGER_MAXSIZEBYTES, clampedValue);
m_fileLogger->setMaxSize(value);
settings()->storeValue(KEY_FILELOGGER_MAXSIZE, std::min(std::max(value, 1), 1000));
}
int Application::fileLoggerAge() const
{
int val = settings()->loadValue(KEY_FILELOGGER_AGE, 1).toInt();
return std::min(std::max(val, 1), 365);
int val = settings()->loadValue(KEY_FILELOGGER_AGE, 6).toInt();
if (val < 1)
return 1;
if (val > 365)
return 365;
return val;
}
void Application::setFileLoggerAge(const int value)
@@ -262,17 +254,17 @@ void Application::setFileLoggerAge(const int value)
int Application::fileLoggerAgeType() const
{
int val = settings()->loadValue(KEY_FILELOGGER_AGETYPE, 1).toInt();
return ((val < 0) || (val > 2)) ? 1 : val;
return (val < 0 || val > 2) ? 1 : val;
}
void Application::setFileLoggerAgeType(const int value)
{
settings()->storeValue(KEY_FILELOGGER_AGETYPE, ((value < 0) || (value > 2)) ? 1 : value);
settings()->storeValue(KEY_FILELOGGER_AGETYPE, (value < 0 || value > 2) ? 1 : value);
}
void Application::processMessage(const QString &message)
{
QStringList params = message.split(PARAMS_SEPARATOR, QString::SkipEmptyParts);
QStringList params = message.split(QLatin1String(PARAMS_SEPARATOR), QString::SkipEmptyParts);
// If Application is not running (i.e., other
// components are not ready) store params
if (m_running)
@@ -281,61 +273,46 @@ void Application::processMessage(const QString &message)
m_paramsQueue.append(params);
}
void Application::runExternalProgram(const BitTorrent::TorrentHandle *torrent) const
void Application::runExternalProgram(BitTorrent::TorrentHandle *const torrent) const
{
QString program = Preferences::instance()->getAutoRunProgram().trimmed();
QString program = Preferences::instance()->getAutoRunProgram();
program.replace("%N", torrent->name());
program.replace("%L", torrent->category());
QStringList tags = torrent->tags().toList();
std::sort(tags.begin(), tags.end(), Utils::String::naturalLessThan<Qt::CaseInsensitive>);
program.replace("%G", tags.join(','));
#if defined(Q_OS_WIN)
const auto chopPathSep = [](const QString &str) -> QString
{
if (str.endsWith('\\'))
return str.mid(0, (str.length() -1));
return str;
};
program.replace("%F", chopPathSep(Utils::Fs::toNativePath(torrent->contentPath())));
program.replace("%R", chopPathSep(Utils::Fs::toNativePath(torrent->rootPath())));
program.replace("%D", chopPathSep(Utils::Fs::toNativePath(torrent->savePath())));
#else
program.replace("%F", Utils::Fs::toNativePath(torrent->contentPath()));
program.replace("%R", Utils::Fs::toNativePath(torrent->rootPath()));
program.replace("%D", Utils::Fs::toNativePath(torrent->savePath()));
#endif
program.replace("%C", QString::number(torrent->filesCount()));
program.replace("%Z", QString::number(torrent->totalSize()));
program.replace("%T", torrent->currentTracker());
program.replace("%I", torrent->hash());
Logger *logger = Logger::instance();
logger->addMessage(tr("Torrent: %1, running external program, command: %2").arg(torrent->name(), program));
logger->addMessage(tr("Torrent: %1, running external program, command: %2").arg(torrent->name()).arg(program));
#if defined(Q_OS_WIN)
std::unique_ptr<wchar_t[]> programWchar(new wchar_t[program.length() + 1] {});
program.toWCharArray(programWchar.get());
#if defined(Q_OS_UNIX)
QProcess::startDetached(QLatin1String("/bin/sh"), {QLatin1String("-c"), program});
#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 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;
}
// Need to split arguments manually because QProcess::startDetached(QString)
// will strip off empty parameters.
// E.g. `python.exe "1" "" "3"` will become `python.exe "1" "3"`
int argCount = 0;
LPWSTR *args = ::CommandLineToArgvW(programWchar.get(), &argCount);
STARTUPINFOW si = {0};
si.cb = sizeof(si);
PROCESS_INFORMATION pi = {0};
QStringList argList;
for (int i = 1; i < argCount; ++i)
argList += QString::fromWCharArray(args[i]);
QProcess::startDetached(QString::fromWCharArray(args[0]), argList);
::LocalFree(args);
WCHAR *arg = new WCHAR[program.size() + 1];
program.toWCharArray(arg);
arg[program.size()] = L'\0';
if (CreateProcessW(NULL, arg, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
delete[] arg;
#else
// Cannot give users shell environment by default, as doing so could
// enable command injection via torrent name and other arguments
// (especially when some automated download mechanism has been setup).
// See: https://github.com/qbittorrent/qBittorrent/issues/10925
QProcess::startDetached(program);
#endif
}
@@ -343,12 +320,12 @@ void Application::runExternalProgram(const BitTorrent::TorrentHandle *torrent) c
void Application::sendNotificationEmail(const BitTorrent::TorrentHandle *torrent)
{
// Prepare mail content
const QString content = tr("Torrent name: %1").arg(torrent->name()) + '\n'
+ tr("Torrent size: %1").arg(Utils::Misc::friendlyUnit(torrent->wantedSize())) + '\n'
const QString content = tr("Torrent name: %1").arg(torrent->name()) + "\n"
+ tr("Torrent size: %1").arg(Utils::Misc::friendlyUnit(torrent->wantedSize())) + "\n"
+ tr("Save path: %1").arg(torrent->savePath()) + "\n\n"
+ tr("The torrent was downloaded in %1.", "The torrent was downloaded in 1 hour and 20 seconds")
.arg(Utils::Misc::userFriendlyDuration(torrent->activeTime())) + "\n\n\n"
+ tr("Thank you for using qBittorrent.") + '\n';
+ tr("Thank you for using qBittorrent.") + "\n";
// Send the notification email
const Preferences *pref = Preferences::instance();
@@ -399,7 +376,7 @@ void Application::allTorrentsFinished()
// do nothing & skip confirm
}
else {
if (!ShutdownConfirmDialog::askForConfirmation(m_window, action)) return;
if (!ShutdownConfirmDlg::askForConfirmation(m_window, action)) return;
}
#endif // DISABLE_GUI
@@ -420,7 +397,7 @@ void Application::allTorrentsFinished()
bool Application::sendParams(const QStringList &params)
{
return sendMessage(params.join(PARAMS_SEPARATOR));
return sendMessage(params.join(QLatin1String(PARAMS_SEPARATOR)));
}
// As program parameters, we can get paths or urls.
@@ -438,7 +415,7 @@ void Application::processParams(const QStringList &params)
BitTorrent::AddTorrentParams torrentParams;
TriStateBool skipTorrentDialog;
for (QString param : params) {
foreach (QString param, params) {
param = param.trimmed();
// Process strings indicating options specified by the user.
@@ -449,7 +426,7 @@ void Application::processParams(const QStringList &params)
}
if (param.startsWith(QLatin1String("@addPaused="))) {
torrentParams.addPaused = param.midRef(11).toInt() ? TriStateBool::True : TriStateBool::False;
torrentParams.addPaused = param.mid(11).toInt() ? TriStateBool::True : TriStateBool::False;
continue;
}
@@ -474,7 +451,7 @@ void Application::processParams(const QStringList &params)
}
if (param.startsWith(QLatin1String("@skipDialog="))) {
skipTorrentDialog = param.midRef(12).toInt() ? TriStateBool::True : TriStateBool::False;
skipTorrentDialog = param.mid(12).toInt() ? TriStateBool::True : TriStateBool::False;
continue;
}
@@ -505,57 +482,38 @@ int Application::exec(const QStringList &params)
GuiIconProvider::initInstance();
#endif
try {
BitTorrent::Session::initInstance();
connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentFinished, this, &Application::torrentFinished);
connect(BitTorrent::Session::instance(), &BitTorrent::Session::allTorrentsFinished, this, &Application::allTorrentsFinished, Qt::QueuedConnection);
BitTorrent::Session::initInstance();
connect(BitTorrent::Session::instance(), SIGNAL(torrentFinished(BitTorrent::TorrentHandle *const)), SLOT(torrentFinished(BitTorrent::TorrentHandle *const)));
connect(BitTorrent::Session::instance(), SIGNAL(allTorrentsFinished()), SLOT(allTorrentsFinished()), Qt::QueuedConnection);
#ifndef DISABLE_COUNTRIES_RESOLUTION
Net::GeoIPManager::initInstance();
Net::GeoIPManager::initInstance();
#endif
ScanFoldersModel::initInstance(this);
ScanFoldersModel::initInstance(this);
#ifndef DISABLE_WEBUI
m_webui = new WebUI;
m_webui = new WebUI;
#ifdef DISABLE_GUI
if (m_webui->isErrored())
return 1;
connect(m_webui, &WebUI::fatalError, this, []() { QCoreApplication::exit(1); });
if (m_webui->isErrored())
return 1;
connect(m_webui, &WebUI::fatalError, this, []() { QCoreApplication::exit(1); });
#endif // DISABLE_GUI
#endif // DISABLE_WEBUI
new RSS::Session; // create RSS::Session singleton
new RSS::AutoDownloader; // create RSS::AutoDownloader singleton
}
catch (const RuntimeError &err) {
#ifdef DISABLE_GUI
fprintf(stderr, "%s", err.what());
#else
QMessageBox msgBox;
msgBox.setIcon(QMessageBox::Critical);
msgBox.setText(tr("Application failed to start."));
msgBox.setInformativeText(err.message());
msgBox.show(); // Need to be shown or to moveToCenter does not work
msgBox.move(Utils::Misc::screenCenter(&msgBox));
msgBox.exec();
#endif
return 1;
}
new RSS::Session; // create RSS::Session singleton
new RSS::AutoDownloader; // create RSS::AutoDownloader singleton
#ifdef DISABLE_GUI
#ifndef DISABLE_WEBUI
Preferences *const pref = Preferences::instance();
Preferences* const pref = Preferences::instance();
// Display some information to the user
const QString mesg = QString("\n******** %1 ********\n").arg(tr("Information"))
+ tr("To control qBittorrent, access the Web UI at %1")
.arg(QString("http://localhost:") + QString::number(pref->getWebUiPort())) + '\n'
+ tr("The Web UI administrator user name is: %1").arg(pref->getWebUiUsername()) + '\n';
printf("%s", qUtf8Printable(mesg));
std::cout << std::endl << "******** " << qPrintable(tr("Information")) << " ********" << std::endl;
std::cout << qPrintable(tr("To control qBittorrent, access the Web UI at http://localhost:%1").arg(QString::number(pref->getWebUiPort()))) << std::endl;
std::cout << qPrintable(tr("The Web UI administrator user name is: %1").arg(pref->getWebUiUsername())) << std::endl;
qDebug() << "Password:" << pref->getWebUiPassword();
if (pref->getWebUiPassword() == "f6fdffe48c908deb0f4c3bd36c032e72") {
const QString warning = tr("The Web UI administrator password is still the default one: %1").arg("adminadmin") + '\n'
+ tr("This is a security risk, please consider changing your password from program preferences.") + '\n';
printf("%s", qUtf8Printable(warning));
std::cout << qPrintable(tr("The Web UI administrator password is still the default one: %1").arg("adminadmin")) << std::endl;
std::cout << qPrintable(tr("This is a security risk, please consider changing your password from program preferences.")) << std::endl;
}
#endif // DISABLE_WEBUI
#else
@@ -640,7 +598,7 @@ bool Application::notify(QObject *receiver, QEvent *event)
void Application::initializeTranslation()
{
Preferences *const pref = Preferences::instance();
Preferences* const pref = Preferences::instance();
// Load translation
QString localeStr = pref->getLocale();
@@ -693,7 +651,7 @@ void Application::shutdownCleanup(QSessionManager &manager)
// According to the qt docs we shouldn't call quit() inside a slot.
// aboutToQuit() is never emitted if the user hits "Cancel" in
// the above dialog.
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
QTimer::singleShot(0, qApp, SLOT(quit()));
}
#endif
@@ -706,7 +664,7 @@ void Application::cleanup()
#ifndef DISABLE_GUI
if (m_window) {
// Hide the window and don't leave it on screen as
// Hide the window and not leave it on screen as
// unresponsive. Also for Windows take the WinId
// after it's hidden, because hide() may cause a
// WinId change.
@@ -714,7 +672,7 @@ void Application::cleanup()
#ifdef Q_OS_WIN
typedef BOOL (WINAPI *PSHUTDOWNBRCREATE)(HWND, LPCWSTR);
const auto shutdownBRCreate = Utils::Misc::loadWinAPI<PSHUTDOWNBRCREATE>("User32.dll", "ShutdownBlockReasonCreate");
PSHUTDOWNBRCREATE shutdownBRCreate = (PSHUTDOWNBRCREATE)::GetProcAddress(::GetModuleHandleW(L"User32.dll"), "ShutdownBlockReasonCreate");
// Only available on Vista+
if (shutdownBRCreate)
shutdownBRCreate((HWND)m_window->effectiveWinId(), tr("Saving torrent progress...").toStdWString().c_str());
@@ -750,14 +708,13 @@ void Application::cleanup()
delete m_fileLogger;
Logger::freeInstance();
IconProvider::freeInstance();
SearchPluginManager::freeInstance();
Utils::Fs::removeDirRecursive(Utils::Fs::tempPath());
#ifndef DISABLE_GUI
if (m_window) {
#ifdef Q_OS_WIN
typedef BOOL (WINAPI *PSHUTDOWNBRDESTROY)(HWND);
const auto shutdownBRDestroy = Utils::Misc::loadWinAPI<PSHUTDOWNBRDESTROY>("User32.dll", "ShutdownBlockReasonDestroy");
PSHUTDOWNBRDESTROY shutdownBRDestroy = (PSHUTDOWNBRDESTROY)::GetProcAddress(::GetModuleHandleW(L"User32.dll"), "ShutdownBlockReasonDestroy");
// Only available on Vista+
if (shutdownBRDestroy)
shutdownBRDestroy((HWND)m_window->effectiveWinId());

View File

@@ -40,13 +40,15 @@ typedef QtSingleApplication BaseApplication;
class MainWindow;
#ifdef Q_OS_WIN
QT_BEGIN_NAMESPACE
class QSessionManager;
QT_END_NAMESPACE
#endif // Q_OS_WIN
#else
#include "qtsinglecoreapplication.h"
typedef QtSingleCoreApplication BaseApplication;
#endif // DISABLE_GUI
#endif
#include "base/utils/misc.h"
#include "cmdoptions.h"
@@ -99,7 +101,7 @@ public:
bool isFileLoggerDeleteOld() const;
void setFileLoggerDeleteOld(bool value);
int fileLoggerMaxSize() const;
void setFileLoggerMaxSize(const int bytes);
void setFileLoggerMaxSize(const int value);
int fileLoggerAge() const;
void setFileLoggerAge(const int value);
int fileLoggerAgeType() const;
@@ -108,9 +110,9 @@ public:
protected:
#ifndef DISABLE_GUI
#ifdef Q_OS_MAC
bool event(QEvent *) override;
bool event(QEvent *);
#endif
bool notify(QObject *receiver, QEvent *event) override;
bool notify(QObject* receiver, QEvent* event);
#endif
private slots:
@@ -144,7 +146,7 @@ private:
void initializeTranslation();
void processParams(const QStringList &params);
void runExternalProgram(const BitTorrent::TorrentHandle *torrent) const;
void runExternalProgram(BitTorrent::TorrentHandle *const torrent) const;
void sendNotificationEmail(const BitTorrent::TorrentHandle *torrent);
void validateCommandLineParameters();
};

View File

@@ -2,7 +2,7 @@
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2016 Eugene Shalygin <eugene.shalygin@gmail.com>
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -26,11 +26,13 @@
* 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.
*
* Contact : chris@qbittorrent.org
*/
#include "cmdoptions.h"
#include <cstdio>
#include <iostream>
#include <QDebug>
#include <QFileInfo>
@@ -41,7 +43,6 @@
#include <QMessageBox>
#endif
#include "base/global.h"
#include "base/utils/misc.h"
#include "base/utils/string.h"
@@ -99,7 +100,7 @@ namespace
};
// Boolean option.
class BoolOption : protected Option
class BoolOption: protected Option
{
public:
constexpr BoolOption(const char *name, char shortcut = 0)
@@ -117,7 +118,7 @@ namespace
{
QString val = env.value(envVarName());
// we accept "1" and "true" (upper or lower cased) as boolean 'true' values
return ((val == QLatin1String("1")) || (val.toUpper() == QLatin1String("TRUE")));
return (val == QLatin1String("1") || val.toUpper() == QLatin1String("TRUE"));
}
QString usage() const
@@ -136,7 +137,7 @@ namespace
}
// Option with string value. May not have a shortcut
struct StringOption : protected Option
struct StringOption: protected Option
{
public:
constexpr StringOption(const char *name)
@@ -183,7 +184,7 @@ namespace
}
// Option with integer value. May not have a shortcut
class IntOption : protected StringOption
class IntOption: protected StringOption
{
public:
constexpr IntOption(const char *name)
@@ -215,7 +216,7 @@ namespace
int res = val.toInt(&ok);
if (!ok) {
qDebug() << QObject::tr("Expected integer number in environment variable '%1', but got '%2'")
.arg(envVarName(), val);
.arg(envVarName()).arg(val);
return defaultValue;
}
return res;
@@ -229,7 +230,7 @@ namespace
// Option that is explicitly set to true or false, and whose value is undefined when unspecified.
// May not have a shortcut.
class TriStateBoolOption : protected Option
class TriStateBoolOption: protected Option
{
public:
constexpr TriStateBoolOption(const char *name, bool defaultValue)
@@ -259,10 +260,10 @@ namespace
else if (parts.size() == 2) {
QString val = parts[1];
if ((val.toUpper() == QLatin1String("TRUE")) || (val == QLatin1String("1"))) {
if (val.toUpper() == QLatin1String("TRUE") || val == QLatin1String("1")) {
return TriStateBool::True;
}
else if ((val.toUpper() == QLatin1String("FALSE")) || (val == QLatin1String("0"))) {
else if (val.toUpper() == QLatin1String("FALSE") || val == QLatin1String("0")) {
return TriStateBool::False;
}
}
@@ -284,15 +285,15 @@ namespace
else if (val == QLatin1String("-1")) {
return TriStateBool::Undefined;
}
else if ((val.toUpper() == QLatin1String("TRUE")) || (val == QLatin1String("1"))) {
else if (val.toUpper() == QLatin1String("TRUE") || val == QLatin1String("1")) {
return TriStateBool::True;
}
else if ((val.toUpper() == QLatin1String("FALSE")) || (val == QLatin1String("0"))) {
else if (val.toUpper() == QLatin1String("FALSE") || val == QLatin1String("0")) {
return TriStateBool::False;
}
else {
qDebug() << QObject::tr("Expected %1 in environment variable '%2', but got '%3'")
.arg(QLatin1String("true|false"), envVarName(), val);
.arg(QLatin1String("true|false")).arg(envVarName()).arg(val);
return TriStateBool::Undefined;
}
}
@@ -359,7 +360,7 @@ QStringList QBtCommandLineParameters::paramList() const
// the user has specified. Here we place special strings that are
// almost certainly not going to collide with a file path or URL
// specified by the user, and placing them at the beginning of the
// string list so that they will be processed before the list of
// string listr so that they will be processed before the list of
// torrent paths or URLs.
if (!savePath.isEmpty())
@@ -403,9 +404,9 @@ QBtCommandLineParameters parseCommandLine(const QStringList &args)
const QString &arg = args[i];
if ((arg.startsWith("--") && !arg.endsWith(".torrent"))
|| (arg.startsWith('-') && (arg.size() == 2))) {
|| (arg.startsWith("-") && (arg.size() == 2))) {
// Parse known parameters
if (arg == SHOW_HELP_OPTION) {
if ((arg == SHOW_HELP_OPTION)) {
result.showHelp = true;
}
#ifndef Q_OS_WIN
@@ -487,7 +488,7 @@ CommandLineParameterError::CommandLineParameterError(const QString &messageForUs
{
}
const QString &CommandLineParameterError::messageForUser() const
const QString& CommandLineParameterError::messageForUser() const
{
return m_messageForUser;
}
@@ -498,9 +499,9 @@ QString wrapText(const QString &text, int initialIndentation = USAGE_TEXT_COLUMN
QStringList lines = {words.first()};
int currentLineMaxLength = wrapAtColumn - initialIndentation;
for (const QString &word : asConst(words.mid(1))) {
foreach (const QString &word, words.mid(1)) {
if (lines.last().length() + word.length() + 1 < currentLineMaxLength) {
lines.last().append(' ' + word);
lines.last().append(" " + word);
}
else {
lines.append(QString(initialIndentation, ' ') + word);
@@ -508,7 +509,7 @@ QString wrapText(const QString &text, int initialIndentation = USAGE_TEXT_COLUMN
}
}
return lines.join('\n');
return lines.join("\n");
}
QString makeUsage(const QString &prgName)
@@ -577,7 +578,7 @@ QString makeUsage(const QString &prgName)
void displayUsage(const QString &prgName)
{
#ifndef Q_OS_WIN
printf("%s\n", qUtf8Printable(makeUsage(prgName)));
std::cout << qPrintable(makeUsage(prgName)) << std::endl;
#else
QMessageBox msgBox(QMessageBox::Information, QObject::tr("Help"), makeUsage(prgName), QMessageBox::Ok);
msgBox.show(); // Need to be shown or to moveToCenter does not work

View File

@@ -2,7 +2,7 @@
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2016 Eugene Shalygin <eugene.shalygin@gmail.com>
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -26,6 +26,8 @@
* 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.
*
* Contact : chris@qbittorrent.org
*/
#ifndef APP_OPTIONS_H
@@ -60,11 +62,11 @@ struct QBtCommandLineParameters
QStringList paramList() const;
};
class CommandLineParameterError : public std::runtime_error
class CommandLineParameterError: public std::runtime_error
{
public:
CommandLineParameterError(const QString &messageForUser);
const QString &messageForUser() const;
const QString& messageForUser() const;
private:
const QString m_messageForUser;

View File

@@ -26,14 +26,11 @@
* exception statement from your version.
*/
#include "filelogger.h"
#include <QDateTime>
#include <QDir>
#include <QFile>
#include <QTextStream>
#include "base/global.h"
#include "filelogger.h"
#include "base/logger.h"
#include "base/utils/fs.h"
@@ -44,17 +41,17 @@ FileLogger::FileLogger(const QString &path, const bool backup, const int maxSize
{
m_flusher.setInterval(0);
m_flusher.setSingleShot(true);
connect(&m_flusher, &QTimer::timeout, this, &FileLogger::flushLog);
connect(&m_flusher, SIGNAL(timeout()), SLOT(flushLog()));
changePath(path);
if (deleteOld)
this->deleteOld(age, ageType);
const Logger *const logger = Logger::instance();
for (const Log::Msg &msg : asConst(logger->getMessages()))
const Logger* const logger = Logger::instance();
foreach (const Log::Msg& msg, logger->getMessages())
addLogMessage(msg);
connect(logger, &Logger::newLogMessage, this, &FileLogger::addLogMessage);
connect(logger, SIGNAL(newLogMessage(const Log::Msg &)), SLOT(addLogMessage(const Log::Msg &)));
}
FileLogger::~FileLogger()
@@ -64,7 +61,7 @@ FileLogger::~FileLogger()
delete m_logFile;
}
void FileLogger::changePath(const QString &newPath)
void FileLogger::changePath(const QString& newPath)
{
QString tmpPath = Utils::Fs::fromNativePath(newPath);
QDir dir(tmpPath);
@@ -86,21 +83,21 @@ void FileLogger::changePath(const QString &newPath)
void FileLogger::deleteOld(const int age, const FileLogAgeType ageType)
{
QDateTime date = QDateTime::currentDateTime();
QDir dir(Utils::Fs::branchPath(m_path));
QDir dir(m_path);
for (const QFileInfo &file : asConst(dir.entryInfoList(QStringList("qbittorrent.log.bak*"), QDir::Files | QDir::Writable, QDir::Time | QDir::Reversed))) {
QDateTime modificationDate = file.lastModified();
switch (ageType) {
case DAYS:
modificationDate = modificationDate.addDays(age);
break;
case MONTHS:
modificationDate = modificationDate.addMonths(age);
break;
default:
modificationDate = modificationDate.addYears(age);
}
if (modificationDate > date)
switch (ageType) {
case DAYS:
date = date.addDays(age);
break;
case MONTHS:
date = date.addMonths(age);
break;
default:
date = date.addYears(age);
}
foreach (const QFileInfo file, dir.entryInfoList(QStringList("qbittorrent.log.bak*"), QDir::Files | QDir::Writable, QDir::Time | QDir::Reversed)) {
if (file.lastModified() < date)
break;
Utils::Fs::forceRemove(file.absoluteFilePath());
}
@@ -138,7 +135,7 @@ void FileLogger::addLogMessage(const Log::Msg &msg)
str << QDateTime::fromMSecsSinceEpoch(msg.timestamp).toString(Qt::ISODate) << " - " << msg.message << endl;
if (m_backup && (m_logFile->size() >= m_maxSize)) {
if (m_backup && (m_logFile->size() >= (m_maxSize * 1024 * 1024))) {
closeLogFile();
int counter = 0;
QString backupLogFilename = m_path + ".bak";
@@ -168,7 +165,7 @@ void FileLogger::openLogFile()
|| !m_logFile->setPermissions(QFile::ReadOwner | QFile::WriteOwner)) {
delete m_logFile;
m_logFile = nullptr;
Logger::instance()->addMessage(tr("An error occurred while trying to open the log file. Logging to file is disabled."), Log::CRITICAL);
Logger::instance()->addMessage(tr("An error occured while trying to open the log file. Logging to file is disabled."), Log::CRITICAL);
}
}

View File

@@ -76,3 +76,4 @@ private:
};
#endif // FILELOGGER_H

View File

@@ -1,7 +1,7 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -25,10 +25,10 @@
* 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.
*
* Contact : chris@qbittorrent.org
*/
#include <cstdlib>
#include <QDebug>
#include <QScopedPointer>
#include <QThread>
@@ -55,28 +55,33 @@ Q_IMPORT_PLUGIN(QICOPlugin)
#endif
#endif // DISABLE_GUI
#include <signal.h>
#ifdef STACKTRACE
#ifdef Q_OS_UNIX
#include <signal.h>
#include <execinfo.h>
#include "stacktrace.h"
#else
#include "stacktrace_win.h"
#include "stacktracedialog.h"
#endif // Q_OS_UNIX
#endif //STACKTRACE
#include "base/preferences.h"
#ifdef STACKTRACE_WIN
#include <signal.h>
#include "stacktrace_win.h"
#include "stacktrace_win_dlg.h"
#endif //STACKTRACE_WIN
#include <cstdlib>
#include <iostream>
#include "application.h"
#include "base/profile.h"
#include "base/utils/misc.h"
#include "application.h"
#include "base/preferences.h"
#include "cmdoptions.h"
#include "upgrade.h"
// Signal handlers
#if defined(Q_OS_UNIX) || defined(STACKTRACE_WIN)
void sigNormalHandler(int signum);
#ifdef STACKTRACE
void sigAbnormalHandler(int signum);
#endif
// sys_signame[] is only defined in BSD
const char *sysSigName[] = {
#if defined(Q_OS_WIN)
@@ -91,9 +96,10 @@ const char *sysSigName[] = {
"SIGPWR", "SIGUNUSED"
#endif
};
#endif
#if !defined Q_OS_WIN && !defined Q_OS_HAIKU
void reportToUser(const char *str);
void reportToUser(const char* str);
#endif
void displayVersion();
@@ -102,6 +108,10 @@ void displayBadArgMessage(const QString &message);
#if !defined(DISABLE_GUI)
void showSplashScreen();
#if defined(Q_OS_UNIX)
void setupDpi();
#endif // Q_OS_UNIX
#endif // DISABLE_GUI
// Main
@@ -116,6 +126,10 @@ int main(int argc, char *argv[])
macMigratePlists();
#endif
#if !defined(DISABLE_GUI) && defined(Q_OS_UNIX)
setupDpi();
#endif
try {
// Create Application
QString appId = QLatin1String("qBittorrent-") + Utils::Misc::getUserIDString();
@@ -155,7 +169,7 @@ int main(int argc, char *argv[])
// Set environment variable
if (!qputenv("QBITTORRENT", QBT_VERSION))
fprintf(stderr, "Couldn't set environment variable...\n");
std::cerr << "Couldn't set environment variable...\n";
#ifndef DISABLE_GUI
if (!userAgreesWithLegalNotice())
@@ -202,7 +216,7 @@ int main(int argc, char *argv[])
// this is the default in Qt6
app->setAttribute(Qt::AA_DisableWindowContextHelpButton);
#endif
#endif // Q_OS_WIN
#endif
#if defined(Q_OS_MAC)
// Since Apple made difficult for users to set PATH, we set here for convenience.
@@ -226,7 +240,7 @@ int main(int argc, char *argv[])
#ifdef DISABLE_GUI
if (params.shouldDaemonize) {
app.reset(); // Destroy current application
if (daemon(1, 0) == 0) {
if ((daemon(1, 0) == 0)) {
app.reset(new Application(appId, argc, argv));
if (app->isRunning()) {
// Another instance had time to start.
@@ -243,9 +257,9 @@ int main(int argc, char *argv[])
showSplashScreen();
#endif
#if defined(Q_OS_UNIX) || defined(STACKTRACE_WIN)
signal(SIGINT, sigNormalHandler);
signal(SIGTERM, sigNormalHandler);
#ifdef STACKTRACE
signal(SIGABRT, sigAbnormalHandler);
signal(SIGSEGV, sigAbnormalHandler);
#endif
@@ -259,7 +273,7 @@ int main(int argc, char *argv[])
}
#if !defined Q_OS_WIN && !defined Q_OS_HAIKU
void reportToUser(const char *str)
void reportToUser(const char* str)
{
const size_t strLen = strlen(str);
if (write(STDERR_FILENO, str, strLen) < static_cast<ssize_t>(strLen)) {
@@ -269,6 +283,7 @@ void reportToUser(const char *str)
}
#endif
#if defined(Q_OS_UNIX) || defined(STACKTRACE_WIN)
void sigNormalHandler(int signum)
{
#if !defined Q_OS_WIN && !defined Q_OS_HAIKU
@@ -282,7 +297,6 @@ void sigNormalHandler(int signum)
qApp->exit(); // unsafe, but exit anyway
}
#ifdef STACKTRACE
void sigAbnormalHandler(int signum)
{
const char *sigName = sysSigName[signum];
@@ -295,41 +309,47 @@ void sigAbnormalHandler(int signum)
reportToUser(sigName);
reportToUser("\n");
print_stacktrace(); // unsafe
#endif
#if defined Q_OS_WIN
StacktraceDialog dlg; // unsafe
#endif // !defined Q_OS_WIN && !defined Q_OS_HAIKU
#ifdef STACKTRACE_WIN
StraceDlg dlg; // unsafe
dlg.setStacktraceString(QLatin1String(sigName), straceWin::getBacktrace());
dlg.exec();
#endif
#endif // STACKTRACE_WIN
signal(signum, SIG_DFL);
raise(signum);
}
#endif // STACKTRACE
#endif // defined(Q_OS_UNIX) || defined(STACKTRACE_WIN)
#if !defined(DISABLE_GUI)
void showSplashScreen()
{
QPixmap splashImg(":/icons/skin/splash.png");
QPainter painter(&splashImg);
QPixmap splash_img(":/icons/skin/splash.png");
QPainter painter(&splash_img);
QString version = QBT_VERSION;
painter.setPen(QPen(Qt::white));
painter.setFont(QFont("Arial", 22, QFont::Black));
painter.drawText(224 - painter.fontMetrics().width(version), 270, version);
QSplashScreen *splash = new QSplashScreen(splashImg);
QSplashScreen *splash = new QSplashScreen(splash_img);
splash->show();
QTimer::singleShot(1500, splash, &QObject::deleteLater);
QTimer::singleShot(1500, splash, SLOT(deleteLater()));
qApp->processEvents();
}
#if defined(Q_OS_UNIX)
void setupDpi()
{
if (qgetenv("QT_AUTO_SCREEN_SCALE_FACTOR").isEmpty())
qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "1");
}
#endif // Q_OS_UNIX
#endif // DISABLE_GUI
void displayVersion()
{
printf("%s %s\n", qUtf8Printable(qApp->applicationName()), QBT_VERSION);
std::cout << qPrintable(qApp->applicationName()) << " " << QBT_VERSION << std::endl;
}
void displayBadArgMessage(const QString &message)
void displayBadArgMessage(const QString& message)
{
QString help = QObject::tr("Run application with -h option to read about command line parameters.");
#ifdef Q_OS_WIN
@@ -339,28 +359,24 @@ void displayBadArgMessage(const QString &message)
msgBox.move(Utils::Misc::screenCenter(&msgBox));
msgBox.exec();
#else
const QString errMsg = QObject::tr("Bad command line: ") + '\n'
+ message + '\n'
+ help + '\n';
fprintf(stderr, "%s", qUtf8Printable(errMsg));
std::cerr << qPrintable(QObject::tr("Bad command line: "));
std::cerr << qPrintable(message) << std::endl;
std::cerr << qPrintable(help) << std::endl;
#endif
}
bool userAgreesWithLegalNotice()
{
Preferences *const pref = Preferences::instance();
Preferences* const pref = Preferences::instance();
if (pref->getAcceptedLegal()) // Already accepted once
return true;
#ifdef DISABLE_GUI
const QString eula = QString("\n*** %1 ***\n").arg(QObject::tr("Legal Notice"))
+ QObject::tr("qBittorrent is a file sharing program. When you run a torrent, its data will be made available to others by means of upload. Any content you share is your sole responsibility.") + "\n\n"
+ QObject::tr("No further notices will be issued.") + "\n\n"
+ QObject::tr("Press %1 key to accept and continue...").arg("'y'") + '\n';
printf("%s", qUtf8Printable(eula));
std::cout << std::endl << "*** " << qPrintable(QObject::tr("Legal Notice")) << " ***" << std::endl;
std::cout << qPrintable(QObject::tr("qBittorrent is a file sharing program. When you run a torrent, its data will be made available to others by means of upload. Any content you share is your sole responsibility.\n\nNo further notices will be issued.")) << std::endl << std::endl;
std::cout << qPrintable(QObject::tr("Press %1 key to accept and continue...").arg("'y'")) << std::endl;
char ret = getchar(); // Read pressed key
if ((ret == 'y') || (ret == 'Y')) {
if (ret == 'y' || ret == 'Y') {
// Save the answer
pref->setAcceptedLegal(true);
return true;
@@ -370,16 +386,16 @@ bool userAgreesWithLegalNotice()
msgBox.setText(QObject::tr("qBittorrent is a file sharing program. When you run a torrent, its data will be made available to others by means of upload. Any content you share is your sole responsibility.\n\nNo further notices will be issued."));
msgBox.setWindowTitle(QObject::tr("Legal notice"));
msgBox.addButton(QObject::tr("Cancel"), QMessageBox::RejectRole);
QAbstractButton *agreeButton = msgBox.addButton(QObject::tr("I Agree"), QMessageBox::AcceptRole);
QAbstractButton *agree_button = msgBox.addButton(QObject::tr("I Agree"), QMessageBox::AcceptRole);
msgBox.show(); // Need to be shown or to moveToCenter does not work
msgBox.move(Utils::Misc::screenCenter(&msgBox));
msgBox.exec();
if (msgBox.clickedButton() == agreeButton) {
if (msgBox.clickedButton() == agree_button) {
// Save the answer
pref->setAcceptedLegal(true);
return true;
}
#endif // DISABLE_GUI
#endif
return false;
}

View File

@@ -8,24 +8,24 @@ set(QBT_QTSINGLEAPPLICATION_SOURCES
qtlocalpeer.cpp
)
if (Qt5Widgets_FOUND)
if (GUI)
list(APPEND QBT_QTSINGLEAPPLICATION_HEADERS qtsingleapplication.h)
list(APPEND QBT_QTSINGLEAPPLICATION_SOURCES qtsingleapplication.cpp)
else (Qt5Widgets_FOUND)
else (GUI)
list(APPEND QBT_QTSINGLEAPPLICATION_HEADERS qtsinglecoreapplication.h)
list(APPEND QBT_QTSINGLEAPPLICATION_SOURCES qtsinglecoreapplication.cpp)
endif (Qt5Widgets_FOUND)
endif (GUI)
add_library(qtsingleapplication STATIC ${QBT_QTSINGLEAPPLICATION_HEADERS} ${QBT_QTSINGLEAPPLICATION_SOURCES})
target_include_directories(qtsingleapplication INTERFACE "${qtsingleapplication_SOURCE_DIR}")
target_link_libraries(qtsingleapplication PRIVATE Qt5::Network)
target_link_qt_components(qtsingleapplication Network)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
target_compile_options(qtsingleapplication PRIVATE "-w") # disable warning for 3rdparty code
endif()
if (Qt5Widgets_FOUND)
target_link_libraries(qtsingleapplication PRIVATE Qt5::Widgets)
endif (Qt5Widgets_FOUND)
if (GUI)
target_link_qt_components(qtsingleapplication Widgets)
endif (GUI)
add_library(QtSingleApplication::QtSingleApplication ALIAS qtsingleapplication)

View File

@@ -101,7 +101,6 @@ QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
#endif
server = new QLocalServer(this);
server->setSocketOptions(QLocalServer::UserAccessOption);
QString lockName = QDir(QDir::tempPath()).absolutePath()
+ QLatin1Char('/') + socketName
+ QLatin1String("-lockfile");
@@ -192,12 +191,6 @@ void QtLocalPeer::receiveConnection()
QByteArray uMsg;
quint32 remaining;
ds >> remaining;
if (remaining > 65535) {
// drop suspiciously large data
delete socket;
return;
}
uMsg.resize(remaining);
int got = 0;
char* uMsgBuf = uMsg.data();

View File

@@ -138,7 +138,7 @@ bool straceWin::makeRelativePath(const QString& dir, QString& file)
QString straceWin::getSourcePathAndLineNumber(HANDLE hProcess, DWORD64 addr)
{
IMAGEHLP_LINE64 line {};
IMAGEHLP_LINE64 line = {0};
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
DWORD dwDisplacement = 0;
@@ -291,7 +291,7 @@ const QString straceWin::getBacktrace()
demangle(funcName);
#endif
// now ihsf.InstructionOffset points to the instruction that follows CALL instruction
// now ihsf.InstructionOffset points to the instruction that follows CALL instuction
// decrease the query address by one byte to point somewhere in the CALL instruction byte sequence
sourceFile = getSourcePathAndLineNumber(hProcess, ihsf.InstructionOffset - 1);
}

View File

@@ -27,21 +27,20 @@
*
*/
#ifndef STACKTRACEDIALOG_H
#define STACKTRACEDIALOG_H
#ifndef STACKTRACE_WIN_DLG_H
#define STACKTRACE_WIN_DLG_H
#include <QString>
#include <QDialog>
#include "base/utils/misc.h"
#include "ui_stacktracedialog.h"
#include "ui_stacktrace_win_dlg.h"
class StacktraceDialog : public QDialog, private Ui::StacktraceDialog
class StraceDlg : public QDialog, private Ui::errorDialog
{
Q_OBJECT
public:
StacktraceDialog(QWidget *parent = nullptr)
StraceDlg(QWidget *parent = nullptr)
: QDialog(parent)
{
setupUi(this);
@@ -84,4 +83,4 @@ public:
}
};
#endif // STACKTRACEDIALOG_H
#endif

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>StacktraceDialog</class>
<widget class="QDialog" name="StacktraceDialog">
<class>errorDialog</class>
<widget class="QDialog" name="errorDialog">
<property name="geometry">
<rect>
<x>0</x>

View File

@@ -29,43 +29,42 @@
#ifndef UPGRADE_H
#define UPGRADE_H
#include <libtorrent/bencode.hpp>
#include <libtorrent/entry.hpp>
#include <libtorrent/version.hpp>
#if LIBTORRENT_VERSION_NUM >= 10100
#include <libtorrent/bdecode.hpp>
#else
#endif
#include <libtorrent/bencode.hpp>
#include <libtorrent/entry.hpp>
#if LIBTORRENT_VERSION_NUM < 10100
#include <libtorrent/lazy_entry.hpp>
#endif
#include <QDir>
#include <QFile>
#include <QRegularExpression>
#include <QString>
#ifndef DISABLE_GUI
#include <QMessageBox>
#endif
#include <QRegExp>
#include <QString>
#ifdef Q_OS_MAC
#include <QSettings>
#endif
#include "base/logger.h"
#include "base/preferences.h"
#include "base/profile.h"
#include "base/utils/fs.h"
#include "base/utils/misc.h"
#include "base/utils/string.h"
#include "base/preferences.h"
bool userAcceptsUpgrade()
{
#ifdef DISABLE_GUI
printf("\n*** %s ***\n", qUtf8Printable(QObject::tr("Upgrade")));
std::cout << std::endl << "*** " << qPrintable(QObject::tr("Upgrade")) << " ***" << std::endl;
char ret = '\0';
do {
printf("%s\n"
, qUtf8Printable(QObject::tr("You updated from an older version that saved things differently. You must migrate to the new saving system. You will not be able to use an older version than v3.3.0 again. Continue? [y/n]")));
std::cout << qPrintable(QObject::tr("You updated from an older version that saved things differently. You must migrate to the new saving system. You will not be able to use an older version than v3.3.0 again. Continue? [y/n]")) << std::endl;
ret = getchar(); // Read pressed key
}
while ((ret != 'y') && (ret != 'Y') && (ret != 'n') && (ret != 'N'));
@@ -83,7 +82,7 @@ bool userAcceptsUpgrade()
msgBox.move(Utils::Misc::screenCenter(&msgBox));
if (msgBox.exec() == QMessageBox::Ok)
return true;
#endif // DISABLE_GUI
#endif
return false;
}
@@ -114,28 +113,12 @@ bool upgradeResumeFile(const QString &filepath, const QVariantHash &oldTorrent =
bool v3_3 = false;
int queuePosition = 0;
QString outFilePath = filepath;
static const QRegularExpression rx(QLatin1String("([A-Fa-f0-9]{40})\\.fastresume\\.(.+)$"));
const QRegularExpressionMatch rxMatch = rx.match(filepath);
if (rxMatch.hasMatch()) {
// Old v3.3.x format had a number at the end indicating the queue position.
// The naming scheme was '<infohash>.fastresume.<queueposition>'.
// However, QSaveFile, which uses QTemporaryFile internally, might leave
// non-commited files behind eg after a crash. These files have the
// naming scheme '<infohash>.fastresume.XXXXXX' where each X is a random
// character. So we detect if the last part is present. Then check if it
// is 6 chars long. If all the 6 chars are digits we assume it is an old
// v3.3.x format. Otherwise it is considered a non-commited fastresume
// and is deleted, because it may be a corrupted/incomplete fastresume.
// NOTE: When the upgrade code is removed, we must continue to perform
// cleanup of non-commited QSaveFile/QTemporaryFile fastresumes
queuePosition = rxMatch.captured(2).toInt();
if ((rxMatch.captured(2).size() == 6) && (queuePosition <= 99999)) {
Utils::Fs::forceRemove(filepath);
return true;
}
QRegExp rx(QLatin1String("([A-Fa-f0-9]{40})\\.fastresume\\.(\\d+)$"));
if (rx.indexIn(filepath) != -1) {
// old v3.3.x format
queuePosition = rx.cap(2).toInt();
v3_3 = true;
outFilePath.replace(QRegularExpression("\\.fastresume\\..+$"), ".fastresume");
outFilePath.replace(QRegExp("\\.\\d+$"), "");
}
else {
queuePosition = fastOld.dict_find_int_value("qBt-queuePosition", 0);
@@ -146,15 +129,6 @@ bool upgradeResumeFile(const QString &filepath, const QVariantHash &oldTorrent =
// in versions < 3.3 we have -1 for seeding torrents, so we convert it to 0
fastNew["qBt-queuePosition"] = (queuePosition >= 0 ? queuePosition : 0);
if (v3_3) {
QFileInfo oldFile(filepath);
QFileInfo newFile(outFilePath);
if (newFile.exists()
&& (oldFile.lastModified() < newFile.lastModified())) {
Utils::Fs::forceRemove(filepath);
return true;
}
}
QFile file2(outFilePath);
QVector<char> out;
libtorrent::bencode(std::back_inserter(out), fastNew);
@@ -179,9 +153,9 @@ bool upgrade(bool ask = true)
// ****************************************************************************************
// Silently converts old v3.3.x .fastresume files
const QStringList backupFiles_3_3 = backupFolderDir.entryList(
QStringList backupFiles_3_3 = backupFolderDir.entryList(
QStringList(QLatin1String("*.fastresume.*")), QDir::Files, QDir::Unsorted);
for (const QString &backupFile : backupFiles_3_3)
foreach (const QString &backupFile, backupFiles_3_3)
upgradeResumeFile(backupFolderDir.absoluteFilePath(backupFile));
// ****************************************************************************************
@@ -197,27 +171,24 @@ bool upgrade(bool ask = true)
if (ask && !userAcceptsUpgrade()) return false;
const QStringList backupFiles = backupFolderDir.entryList(
QStringList backupFiles = backupFolderDir.entryList(
QStringList(QLatin1String("*.fastresume")), QDir::Files, QDir::Unsorted);
const QRegularExpression rx(QLatin1String("^([A-Fa-f0-9]{40})\\.fastresume$"));
for (const QString &backupFile : backupFiles) {
const QRegularExpressionMatch rxMatch = rx.match(backupFile);
if (rxMatch.hasMatch()) {
const QString hashStr = rxMatch.captured(1);
if (upgradeResumeFile(backupFolderDir.absoluteFilePath(backupFile), oldResumeData[hashStr].toHash()))
oldResumeData.remove(hashStr);
QRegExp rx(QLatin1String("^([A-Fa-f0-9]{40})\\.fastresume$"));
foreach (QString backupFile, backupFiles) {
if (rx.indexIn(backupFile) != -1) {
if (upgradeResumeFile(backupFolderDir.absoluteFilePath(backupFile), oldResumeData[rx.cap(1)].toHash()))
oldResumeData.remove(rx.cap(1));
else
Logger::instance()->addMessage(QObject::tr("Couldn't migrate torrent with hash: %1").arg(hashStr), Log::WARNING);
Logger::instance()->addMessage(QObject::tr("Couldn't migrate torrent with hash: %1").arg(rx.cap(1)), Log::WARNING);
}
else {
Logger::instance()->addMessage(QObject::tr("Couldn't migrate torrent. Invalid fastresume file name: %1").arg(backupFile), Log::WARNING);
}
}
for (auto i = oldResumeData.cbegin(); i != oldResumeData.cend(); ++i) {
const QVariantHash oldTorrent = i.value().toHash();
foreach (const QString &hash, oldResumeData.keys()) {
QVariantHash oldTorrent = oldResumeData[hash].toHash();
if (oldTorrent.value("is_magnet", false).toBool()) {
const QString &hash = i.key();
libtorrent::entry resumeData;
resumeData["qBt-magnetUri"] = oldTorrent.value("magnet_uri").toString().toStdString();
resumeData["qBt-paused"] = false;
@@ -265,7 +236,7 @@ void migratePlistToIni(const QString &application)
plistFile->setFallbacksEnabled(false);
const QStringList plist = plistFile->allKeys();
if (!plist.isEmpty()) {
for (const QString &key : plist)
foreach (const QString &key, plist)
iniFile.setValue(key, plistFile->value(key));
plistFile->clear();
}
@@ -299,6 +270,6 @@ void migrateRSS()
qBTRSSLegacy->remove("old_items");
}
}
#endif // DISABLE_GUI
#endif
#endif // UPGRADE_H

View File

@@ -1,10 +1,8 @@
find_package(ZLIB 1.2.5.2 REQUIRED)
add_library(qbt_base STATIC
# headers
set(QBT_BASE_HEADERS
bittorrent/addtorrentparams.h
bittorrent/cachestatus.h
bittorrent/filepriority.h
bittorrent/infohash.h
bittorrent/magneturi.h
bittorrent/peerinfo.h
@@ -21,7 +19,6 @@ bittorrent/torrentinfo.h
bittorrent/tracker.h
bittorrent/trackerentry.h
http/connection.h
http/httperror.h
http/irequesthandler.h
http/requestparser.h
http/responsebuilder.h
@@ -46,11 +43,6 @@ rss/rss_feed.h
rss/rss_folder.h
rss/rss_item.h
rss/rss_session.h
search/searchdownloadhandler.h
search/searchhandler.h
search/searchpluginmanager.h
utils/bytearray.h
utils/foreignapps.h
utils/fs.h
utils/gzip.h
utils/misc.h
@@ -58,9 +50,7 @@ utils/net.h
utils/random.h
utils/string.h
utils/version.h
algorithm.h
asyncfilestorage.h
exceptions.h
filesystemwatcher.h
global.h
iconprovider.h
@@ -69,15 +59,16 @@ logger.h
preferences.h
profile.h
scanfoldersmodel.h
searchengine.h
settingsstorage.h
torrentfileguard.h
torrentfilter.h
tristatebool.h
types.h
unicodestrings.h
)
# sources
bittorrent/filepriority.cpp
set(QBT_BASE_SOURCES
bittorrent/infohash.cpp
bittorrent/magneturi.cpp
bittorrent/peerinfo.cpp
@@ -93,7 +84,6 @@ bittorrent/torrentinfo.cpp
bittorrent/tracker.cpp
bittorrent/trackerentry.cpp
http/connection.cpp
http/httperror.cpp
http/requestparser.cpp
http/responsebuilder.cpp
http/responsegenerator.cpp
@@ -116,11 +106,6 @@ rss/rss_feed.cpp
rss/rss_folder.cpp
rss/rss_item.cpp
rss/rss_session.cpp
search/searchdownloadhandler.cpp
search/searchhandler.cpp
search/searchpluginmanager.cpp
utils/bytearray.cpp
utils/foreignapps.cpp
utils/fs.cpp
utils/gzip.cpp
utils/misc.cpp
@@ -128,33 +113,29 @@ utils/net.cpp
utils/random.cpp
utils/string.cpp
asyncfilestorage.cpp
exceptions.cpp
filesystemwatcher.cpp
iconprovider.cpp
logger.cpp
preferences.cpp
profile.cpp
scanfoldersmodel.cpp
searchengine.cpp
settingsstorage.cpp
torrentfileguard.cpp
torrentfilter.cpp
tristatebool.cpp
)
target_link_libraries(qbt_base
PRIVATE
ZLIB::ZLIB
PUBLIC
LibtorrentRasterbar::torrent-rasterbar
Qt5::Core Qt5::Network Qt5::Xml
)
add_library(qbt_base STATIC ${QBT_BASE_HEADERS} ${QBT_BASE_SOURCES})
target_link_libraries(qbt_base PRIVATE ZLIB::ZLIB PUBLIC LibtorrentRasterbar::LibTorrent)
target_link_qt_components(qbt_base PUBLIC Core Network Xml)
if (Qt5Widgets_FOUND)
if (GUI)
target_link_libraries(qbt_base PUBLIC Qt5::Gui Qt5::Widgets)
endif (Qt5Widgets_FOUND)
endif (GUI)
if (Qt5DBus_FOUND)
target_link_libraries(qbt_base PRIVATE Qt5::DBus)
if (DBUS)
target_link_qt_components(qbt_base PRIVATE DBus)
endif ()
if (APPLE)

View File

@@ -1,41 +0,0 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018 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.
*/
#pragma once
namespace Dict
{
// To be used with QMap, QHash and it's variants
template <typename Dictionary, typename BinaryPredicate>
void removeIf(Dictionary &&dict, BinaryPredicate p)
{
auto it = dict.begin();
while (it != dict.end())
it = (p(it.key(), it.value()) ? dict.erase(it) : it + 1);
}
}

View File

@@ -38,12 +38,12 @@ AsyncFileStorage::AsyncFileStorage(const QString &storageFolderPath, QObject *pa
, m_lockFile(m_storageDir.absoluteFilePath(QStringLiteral("storage.lock")))
{
if (!m_storageDir.mkpath(m_storageDir.absolutePath()))
throw AsyncFileStorageError {tr("Could not create directory '%1'.")
.arg(m_storageDir.absolutePath())};
throw AsyncFileStorageError(
QString("Could not create directory '%1'.").arg(m_storageDir.absolutePath()));
// TODO: This folder locking approach does not work for UNIX systems. Implement it.
if (!m_lockFile.open(QFile::WriteOnly))
throw AsyncFileStorageError {m_lockFile.errorString()};
throw AsyncFileStorageError(m_lockFile.errorString());
}
AsyncFileStorage::~AsyncFileStorage()
@@ -76,3 +76,13 @@ void AsyncFileStorage::store_impl(const QString &fileName, const QByteArray &dat
}
}
}
AsyncFileStorageError::AsyncFileStorageError(const QString &message)
: std::runtime_error(message.toUtf8().data())
{
}
QString AsyncFileStorageError::message() const
{
return what();
}

View File

@@ -28,22 +28,22 @@
#pragma once
#include <stdexcept>
#include <QDir>
#include <QFile>
#include <QObject>
#include "base/exceptions.h"
class AsyncFileStorageError : public RuntimeError
class AsyncFileStorageError: public std::runtime_error
{
public:
using RuntimeError::RuntimeError;
explicit AsyncFileStorageError(const QString &message);
QString message() const;
};
class AsyncFileStorage : public QObject
class AsyncFileStorage: public QObject
{
Q_OBJECT
Q_DISABLE_COPY(AsyncFileStorage)
public:
explicit AsyncFileStorage(const QString &storageFolderPath, QObject *parent = nullptr);

View File

@@ -1,139 +1,124 @@
HEADERS += \
$$PWD/algorithm.h \
$$PWD/asyncfilestorage.h \
$$PWD/bittorrent/addtorrentparams.h \
$$PWD/bittorrent/cachestatus.h \
$$PWD/bittorrent/filepriority.h \
$$PWD/bittorrent/infohash.h \
$$PWD/bittorrent/magneturi.h \
$$PWD/bittorrent/peerinfo.h \
$$PWD/bittorrent/private/bandwidthscheduler.h \
$$PWD/bittorrent/private/filterparserthread.h \
$$PWD/bittorrent/private/resumedatasavingmanager.h \
$$PWD/bittorrent/private/speedmonitor.h \
$$PWD/bittorrent/private/statistics.h \
$$PWD/bittorrent/session.h \
$$PWD/bittorrent/sessionstatus.h \
$$PWD/bittorrent/torrentcreatorthread.h \
$$PWD/bittorrent/torrenthandle.h \
$$PWD/bittorrent/torrentinfo.h \
$$PWD/bittorrent/tracker.h \
$$PWD/bittorrent/trackerentry.h \
$$PWD/exceptions.h \
$$PWD/types.h \
$$PWD/tristatebool.h \
$$PWD/filesystemwatcher.h \
$$PWD/global.h \
$$PWD/http/connection.h \
$$PWD/http/httperror.h \
$$PWD/logger.h \
$$PWD/settingsstorage.h \
$$PWD/settingvalue.h \
$$PWD/preferences.h \
$$PWD/indexrange.h \
$$PWD/iconprovider.h \
$$PWD/http/irequesthandler.h \
$$PWD/http/connection.h \
$$PWD/http/requestparser.h \
$$PWD/http/responsebuilder.h \
$$PWD/http/responsegenerator.h \
$$PWD/http/server.h \
$$PWD/http/types.h \
$$PWD/iconprovider.h \
$$PWD/indexrange.h \
$$PWD/logger.h \
$$PWD/http/responsebuilder.h \
$$PWD/net/dnsupdater.h \
$$PWD/net/downloadhandler.h \
$$PWD/net/downloadmanager.h \
$$PWD/net/downloadhandler.h \
$$PWD/net/geoipmanager.h \
$$PWD/net/portforwarder.h \
$$PWD/net/private/geoipdatabase.h \
$$PWD/net/proxyconfigurationmanager.h \
$$PWD/net/reverseresolution.h \
$$PWD/net/smtp.h \
$$PWD/preferences.h \
$$PWD/private/profile_p.h \
$$PWD/profile.h \
$$PWD/rss/private/rss_parser.h \
$$PWD/net/private/geoipdatabase.h \
$$PWD/bittorrent/addtorrentparams.h \
$$PWD/bittorrent/infohash.h \
$$PWD/bittorrent/session.h \
$$PWD/bittorrent/sessionstatus.h \
$$PWD/bittorrent/cachestatus.h \
$$PWD/bittorrent/magneturi.h \
$$PWD/bittorrent/torrentinfo.h \
$$PWD/bittorrent/torrenthandle.h \
$$PWD/bittorrent/peerinfo.h \
$$PWD/bittorrent/trackerentry.h \
$$PWD/bittorrent/tracker.h \
$$PWD/bittorrent/torrentcreatorthread.h \
$$PWD/bittorrent/private/speedmonitor.h \
$$PWD/bittorrent/private/bandwidthscheduler.h \
$$PWD/bittorrent/private/filterparserthread.h \
$$PWD/bittorrent/private/statistics.h \
$$PWD/bittorrent/private/resumedatasavingmanager.h \
$$PWD/rss/rss_article.h \
$$PWD/rss/rss_autodownloader.h \
$$PWD/rss/rss_autodownloadrule.h \
$$PWD/rss/rss_item.h \
$$PWD/rss/rss_feed.h \
$$PWD/rss/rss_folder.h \
$$PWD/rss/rss_item.h \
$$PWD/rss/rss_session.h \
$$PWD/scanfoldersmodel.h \
$$PWD/search/searchhandler.h \
$$PWD/search/searchdownloadhandler.h \
$$PWD/search/searchpluginmanager.h \
$$PWD/settingsstorage.h \
$$PWD/settingvalue.h \
$$PWD/torrentfileguard.h \
$$PWD/torrentfilter.h \
$$PWD/tristatebool.h \
$$PWD/types.h \
$$PWD/unicodestrings.h \
$$PWD/utils/bytearray.h \
$$PWD/utils/foreignapps.h \
$$PWD/rss/rss_autodownloader.h \
$$PWD/rss/rss_autodownloadrule.h \
$$PWD/rss/private/rss_parser.h \
$$PWD/utils/fs.h \
$$PWD/utils/gzip.h \
$$PWD/utils/misc.h \
$$PWD/utils/net.h \
$$PWD/utils/random.h \
$$PWD/utils/string.h \
$$PWD/utils/version.h
$$PWD/utils/version.h \
$$PWD/profile.h \
$$PWD/private/profile_p.h \
$$PWD/unicodestrings.h \
$$PWD/torrentfileguard.h \
$$PWD/torrentfilter.h \
$$PWD/scanfoldersmodel.h \
$$PWD/searchengine.h \
$$PWD/global.h
SOURCES += \
$$PWD/asyncfilestorage.cpp \
$$PWD/bittorrent/filepriority.cpp \
$$PWD/bittorrent/infohash.cpp \
$$PWD/bittorrent/magneturi.cpp \
$$PWD/bittorrent/peerinfo.cpp \
$$PWD/bittorrent/private/bandwidthscheduler.cpp \
$$PWD/bittorrent/private/filterparserthread.cpp \
$$PWD/bittorrent/private/resumedatasavingmanager.cpp \
$$PWD/bittorrent/private/speedmonitor.cpp \
$$PWD/bittorrent/private/statistics.cpp \
$$PWD/bittorrent/session.cpp \
$$PWD/bittorrent/torrentcreatorthread.cpp \
$$PWD/bittorrent/torrenthandle.cpp \
$$PWD/bittorrent/torrentinfo.cpp \
$$PWD/bittorrent/tracker.cpp \
$$PWD/bittorrent/trackerentry.cpp \
$$PWD/exceptions.cpp \
$$PWD/tristatebool.cpp \
$$PWD/filesystemwatcher.cpp \
$$PWD/logger.cpp \
$$PWD/settingsstorage.cpp \
$$PWD/preferences.cpp \
$$PWD/iconprovider.cpp \
$$PWD/http/connection.cpp \
$$PWD/http/httperror.cpp \
$$PWD/http/requestparser.cpp \
$$PWD/http/responsebuilder.cpp \
$$PWD/http/responsegenerator.cpp \
$$PWD/http/server.cpp \
$$PWD/iconprovider.cpp \
$$PWD/logger.cpp \
$$PWD/http/responsebuilder.cpp \
$$PWD/net/dnsupdater.cpp \
$$PWD/net/downloadhandler.cpp \
$$PWD/net/downloadmanager.cpp \
$$PWD/net/downloadhandler.cpp \
$$PWD/net/geoipmanager.cpp \
$$PWD/net/portforwarder.cpp \
$$PWD/net/private/geoipdatabase.cpp \
$$PWD/net/proxyconfigurationmanager.cpp \
$$PWD/net/reverseresolution.cpp \
$$PWD/net/smtp.cpp \
$$PWD/preferences.cpp \
$$PWD/private/profile_p.cpp \
$$PWD/profile.cpp \
$$PWD/rss/private/rss_parser.cpp \
$$PWD/net/private/geoipdatabase.cpp \
$$PWD/bittorrent/infohash.cpp \
$$PWD/bittorrent/session.cpp \
$$PWD/bittorrent/magneturi.cpp \
$$PWD/bittorrent/torrentinfo.cpp \
$$PWD/bittorrent/torrenthandle.cpp \
$$PWD/bittorrent/peerinfo.cpp \
$$PWD/bittorrent/trackerentry.cpp \
$$PWD/bittorrent/tracker.cpp \
$$PWD/bittorrent/torrentcreatorthread.cpp \
$$PWD/bittorrent/private/speedmonitor.cpp \
$$PWD/bittorrent/private/bandwidthscheduler.cpp \
$$PWD/bittorrent/private/filterparserthread.cpp \
$$PWD/bittorrent/private/statistics.cpp \
$$PWD/bittorrent/private/resumedatasavingmanager.cpp \
$$PWD/rss/rss_article.cpp \
$$PWD/rss/rss_autodownloader.cpp \
$$PWD/rss/rss_autodownloadrule.cpp \
$$PWD/rss/rss_item.cpp \
$$PWD/rss/rss_feed.cpp \
$$PWD/rss/rss_folder.cpp \
$$PWD/rss/rss_item.cpp \
$$PWD/rss/rss_session.cpp \
$$PWD/scanfoldersmodel.cpp \
$$PWD/search/searchdownloadhandler.cpp \
$$PWD/search/searchhandler.cpp \
$$PWD/search/searchpluginmanager.cpp \
$$PWD/settingsstorage.cpp \
$$PWD/torrentfileguard.cpp \
$$PWD/torrentfilter.cpp \
$$PWD/tristatebool.cpp \
$$PWD/utils/bytearray.cpp \
$$PWD/utils/foreignapps.cpp \
$$PWD/rss/rss_autodownloader.cpp \
$$PWD/rss/rss_autodownloadrule.cpp \
$$PWD/rss/private/rss_parser.cpp \
$$PWD/utils/fs.cpp \
$$PWD/utils/gzip.cpp \
$$PWD/utils/misc.cpp \
$$PWD/utils/net.cpp \
$$PWD/utils/random.cpp \
$$PWD/utils/string.cpp
$$PWD/utils/string.cpp \
$$PWD/profile.cpp \
$$PWD/private/profile_p.cpp \
$$PWD/torrentfileguard.cpp \
$$PWD/torrentfilter.cpp \
$$PWD/scanfoldersmodel.cpp \
$$PWD/searchengine.cpp

View File

@@ -1,46 +0,0 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018 Thomas Piccirello <thomas.piccirello@gmail.com>
*
* 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 "filepriority.h"
namespace BitTorrent
{
bool isValidFilePriority(const BitTorrent::FilePriority priority)
{
switch (priority) {
case BitTorrent::FilePriority::Ignored:
case BitTorrent::FilePriority::Normal:
case BitTorrent::FilePriority::High:
case BitTorrent::FilePriority::Maximum:
case BitTorrent::FilePriority::Mixed:
return true;
default:
return false;
}
}
}

View File

@@ -1,43 +0,0 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018 Thomas Piccirello <thomas.piccirello@gmail.com>
*
* 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.
*/
#pragma once
namespace BitTorrent
{
enum class FilePriority : int
{
Ignored = 0,
Normal = 1,
High = 6,
Maximum = 7,
Mixed = -1
};
bool isValidFilePriority(BitTorrent::FilePriority priority);
}

View File

@@ -26,9 +26,8 @@
* exception statement from your version.
*/
#include "infohash.h"
#include <QHash>
#include "infohash.h"
using namespace BitTorrent;
@@ -92,7 +91,7 @@ bool InfoHash::operator!=(const InfoHash &other) const
return (m_nativeHash != other.m_nativeHash);
}
uint BitTorrent::qHash(const InfoHash &key, uint seed)
uint qHash(const InfoHash &key, uint seed)
{
return qHash(static_cast<QString>(key), seed);
}

View File

@@ -29,8 +29,8 @@
#ifndef BITTORRENT_INFOHASH_H
#define BITTORRENT_INFOHASH_H
#include <libtorrent/sha1_hash.hpp>
#include <QString>
#include <libtorrent/sha1_hash.hpp>
namespace BitTorrent
{
@@ -54,8 +54,8 @@ namespace BitTorrent
libtorrent::sha1_hash m_nativeHash;
QString m_hashString;
};
uint qHash(const InfoHash &key, uint seed);
}
uint qHash(const BitTorrent::InfoHash &key, uint seed);
#endif // BITTORRENT_INFOHASH_H

View File

@@ -26,17 +26,16 @@
* exception statement from your version.
*/
#include "magneturi.h"
#include <QByteArray>
#include <QRegExp>
#include <QStringList>
#include <libtorrent/bencode.hpp>
#include <libtorrent/error_code.hpp>
#include <libtorrent/magnet_uri.hpp>
#include <QByteArray>
#include <QRegularExpression>
#include <QStringList>
#include "base/utils/string.h"
#include "magneturi.h"
namespace
{
@@ -46,7 +45,7 @@ namespace
rawBc = rawBc.mid(8); // skip bc://bt/
rawBc = QByteArray::fromBase64(rawBc); // Decode base64
// Format is now AA/url_encoded_filename/size_bytes/info_hash/ZZ
QStringList parts = QString(rawBc).split('/');
QStringList parts = QString(rawBc).split("/");
if (parts.size() != 5) return QString();
QString filename = parts.at(1);
@@ -70,8 +69,8 @@ MagnetUri::MagnetUri(const QString &source)
qDebug("Creating magnet link from bc link");
m_url = bcLinkToMagnet(source);
}
else if (((source.size() == 40) && !source.contains(QRegularExpression("[^0-9A-Fa-f]")))
|| ((source.size() == 32) && !source.contains(QRegularExpression("[^2-7A-Za-z]")))) {
else if (((source.size() == 40) && !source.contains(QRegExp("[^0-9A-Fa-f]")))
|| ((source.size() == 32) && !source.contains(QRegExp("[^2-7A-Za-z]")))) {
m_url = "magnet:?xt=urn:btih:" + source;
}
@@ -83,10 +82,10 @@ MagnetUri::MagnetUri(const QString &source)
m_hash = m_addTorrentParams.info_hash;
m_name = QString::fromStdString(m_addTorrentParams.name);
for (const std::string &tracker : m_addTorrentParams.trackers)
foreach (const std::string &tracker, m_addTorrentParams.trackers)
m_trackers.append(QString::fromStdString(tracker));
for (const std::string &urlSeed : m_addTorrentParams.url_seeds)
foreach (const std::string &urlSeed, m_addTorrentParams.url_seeds)
m_urlSeeds.append(QUrl(urlSeed.c_str()));
}

View File

@@ -246,8 +246,8 @@ QString PeerInfo::connectionType() const
void PeerInfo::calcRelevance(const TorrentHandle *torrent)
{
const QBitArray allPieces = torrent->pieces();
const QBitArray peerPieces = pieces();
const QBitArray &allPieces = torrent->pieces();
const QBitArray &peerPieces = pieces();
int localMissing = 0;
int remoteHaves = 0;
@@ -273,20 +273,18 @@ qreal PeerInfo::relevance() const
void PeerInfo::determineFlags()
{
QStringList flagsDescriptionList;
if (isInteresting()) {
// d = Your client wants to download, but peer doesn't want to send (interested and choked)
if (isRemoteChocked()) {
m_flags += "d ";
flagsDescriptionList += "d = "
+ tr("Interested(local) and Choked(peer)");
m_flagsDescription += tr("interested(local) and choked(peer)");
m_flagsDescription += ", ";
}
else {
// D = Currently downloading (interested and not choked)
m_flags += "D ";
flagsDescriptionList += "D = "
+ tr("interested(local) and unchoked(peer)");
m_flagsDescription += tr("interested(local) and unchoked(peer)");
m_flagsDescription += ", ";
}
}
@@ -294,95 +292,97 @@ void PeerInfo::determineFlags()
// u = Peer wants your client to upload, but your client doesn't want to (interested and choked)
if (isChocked()) {
m_flags += "u ";
flagsDescriptionList += "u = "
+ tr("interested(peer) and choked(local)");
m_flagsDescription += tr("interested(peer) and choked(local)");
m_flagsDescription += ", ";
}
else {
// U = Currently uploading (interested and not choked)
m_flags += "U ";
flagsDescriptionList += "U = "
+ tr("interested(peer) and unchoked(local)");
m_flagsDescription += tr("interested(peer) and unchoked(local)");
m_flagsDescription += ", ";
}
}
// O = Optimistic unchoke
if (optimisticUnchoke()) {
m_flags += "O ";
flagsDescriptionList += "O = "
+ tr("optimistic unchoke");
m_flagsDescription += tr("optimistic unchoke");
m_flagsDescription += ", ";
}
// S = Peer is snubbed
if (isSnubbed()) {
m_flags += "S ";
flagsDescriptionList += "S = "
+ tr("peer snubbed");
m_flagsDescription += tr("peer snubbed");
m_flagsDescription += ", ";
}
// I = Peer is an incoming connection
if (!isLocalConnection()) {
m_flags += "I ";
flagsDescriptionList += "I = "
+ tr("incoming connection");
m_flagsDescription += tr("incoming connection");
m_flagsDescription += ", ";
}
// K = Peer is unchoking your client, but your client is not interested
if (!isRemoteChocked() && !isInteresting()) {
m_flags += "K ";
flagsDescriptionList += "K = "
+ tr("not interested(local) and unchoked(peer)");
m_flagsDescription += tr("not interested(local) and unchoked(peer)");
m_flagsDescription += ", ";
}
// ? = Your client unchoked the peer but the peer is not interested
if (!isChocked() && !isRemoteInterested()) {
m_flags += "? ";
flagsDescriptionList += "? = "
+ tr("not interested(peer) and unchoked(local)");
m_flagsDescription += tr("not interested(peer) and unchoked(local)");
m_flagsDescription += ", ";
}
// X = Peer was included in peerlists obtained through Peer Exchange (PEX)
if (fromPeX()) {
m_flags += "X ";
flagsDescriptionList += "X = "
+ tr("peer from PEX");
m_flagsDescription += tr("peer from PEX");
m_flagsDescription += ", ";
}
// H = Peer was obtained through DHT
if (fromDHT()) {
m_flags += "H ";
flagsDescriptionList += "H = "
+ tr("peer from DHT");
m_flagsDescription += tr("peer from DHT");
m_flagsDescription += ", ";
}
// E = Peer is using Protocol Encryption (all traffic)
if (isRC4Encrypted()) {
m_flags += "E ";
flagsDescriptionList += "E = "
+ tr("encrypted traffic");
m_flagsDescription += tr("encrypted traffic");
m_flagsDescription += ", ";
}
// e = Peer is using Protocol Encryption (handshake)
if (isPlaintextEncrypted()) {
m_flags += "e ";
flagsDescriptionList += "e = "
+ tr("encrypted handshake");
m_flagsDescription += tr("encrypted handshake");
m_flagsDescription += ", ";
}
// P = Peer is using uTorrent uTP
if (useUTPSocket()) {
m_flags += "P ";
flagsDescriptionList += "P = "
+ QString::fromUtf8(C_UTP);
m_flagsDescription += QString::fromUtf8(C_UTP);
m_flagsDescription += ", ";
}
// L = Peer is local
if (fromLSD()) {
m_flags += 'L';
flagsDescriptionList += "L = "
+ tr("peer from LSD");
m_flags += "L";
m_flagsDescription += tr("peer from LSD");
}
m_flags = m_flags.trimmed();
m_flagsDescription = flagsDescriptionList.join('\n');
m_flagsDescription = m_flagsDescription.trimmed();
if (m_flagsDescription.endsWith(',', Qt::CaseInsensitive))
m_flagsDescription.chop(1);
}
QString PeerInfo::flags() const

View File

@@ -55,7 +55,7 @@ void BandwidthScheduler::start()
bool BandwidthScheduler::isTimeForAlternative() const
{
const Preferences *const pref = Preferences::instance();
const Preferences* const pref = Preferences::instance();
QTime start = pref->getSchedulerStartTime();
QTime end = pref->getSchedulerEndTime();

View File

@@ -33,7 +33,7 @@
#include <QObject>
#include <QTimer>
class BandwidthScheduler : public QObject
class BandwidthScheduler: public QObject
{
Q_OBJECT
Q_DISABLE_COPY(BandwidthScheduler)

View File

@@ -1,5 +1,5 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Bittorrent Client using Qt and libt.
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
@@ -147,13 +147,13 @@ int FilterParserThread::parseDATFilterFile()
if (bytesRead < 0)
break;
int dataSize = bytesRead + offset;
if ((bytesRead == 0) && (dataSize == 0))
if (bytesRead == 0 && dataSize == 0)
break;
for (start = 0; start < dataSize; ++start) {
endOfLine = -1;
// The file might have ended without the last line having a newline
if (!((bytesRead == 0) && (dataSize > 0))) {
if (!(bytesRead == 0 && dataSize > 0)) {
for (int i = start; i < dataSize; ++i) {
if (buffer[i] == '\n') {
endOfLine = i;
@@ -295,13 +295,13 @@ int FilterParserThread::parseP2PFilterFile()
if (bytesRead < 0)
break;
int dataSize = bytesRead + offset;
if ((bytesRead == 0) && (dataSize == 0))
if (bytesRead == 0 && dataSize == 0)
break;
for (start = 0; start < dataSize; ++start) {
endOfLine = -1;
// The file might have ended without the last line having a newline
if (!((bytesRead == 0) && (dataSize > 0))) {
if (!(bytesRead == 0 && dataSize > 0)) {
for (int i = start; i < dataSize; ++i) {
if (buffer[i] == '\n') {
endOfLine = i;
@@ -407,24 +407,24 @@ int FilterParserThread::parseP2PFilterFile()
int FilterParserThread::getlineInStream(QDataStream &stream, std::string &name, char delim)
{
char c;
int totalRead = 0;
int total_read = 0;
int read;
do {
read = stream.readRawData(&c, 1);
totalRead += read;
total_read += read;
if (read > 0) {
if (c != delim) {
name += c;
}
else {
// Delim found
return totalRead;
return total_read;
}
}
}
while (read > 0);
while(read > 0);
return totalRead;
return total_read;
}
// Parser for PeerGuardian ip filter in p2p format
@@ -455,7 +455,7 @@ int FilterParserThread::parseP2BFilterFile()
unsigned int start, end;
std::string name;
while (getlineInStream(stream, name, '\0') && !m_abort) {
while(getlineInStream(stream, name, '\0') && !m_abort) {
if (!stream.readRawData(reinterpret_cast<char*>(&start), sizeof(start))
|| !stream.readRawData(reinterpret_cast<char*>(&end), sizeof(end))) {
LogMsg(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
@@ -610,7 +610,7 @@ int FilterParserThread::findAndNullDelimiter(char *const data, char delimiter, i
return -1;
}
int FilterParserThread::trim(char *const data, int start, int end)
int FilterParserThread::trim(char* const data, int start, int end)
{
if (start >= end) return start;
int newStart = start;

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015, 2018 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015 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
@@ -26,36 +26,30 @@
* exception statement from your version.
*/
#include "resumedatasavingmanager.h"
#include <QDebug>
#include <QSaveFile>
#include "base/logger.h"
#include "base/utils/fs.h"
#include "resumedatasavingmanager.h"
ResumeDataSavingManager::ResumeDataSavingManager(const QString &resumeFolderPath)
: m_resumeDataDir(resumeFolderPath)
{
}
void ResumeDataSavingManager::save(const QString &filename, const QByteArray &data) const
void ResumeDataSavingManager::saveResumeData(QString infoHash, QByteArray data) const
{
const QString filepath = m_resumeDataDir.absoluteFilePath(filename);
QString filename = QString("%1.fastresume").arg(infoHash);
QString filepath = m_resumeDataDir.absoluteFilePath(filename);
QSaveFile file {filepath};
if (file.open(QIODevice::WriteOnly)) {
file.write(data);
if (!file.commit()) {
Logger::instance()->addMessage(QString("Couldn't save data in '%1'. Error: %2")
.arg(filepath, file.errorString()), Log::WARNING);
qDebug() << "Saving resume data in" << filepath;
QSaveFile resumeFile(filepath);
if (resumeFile.open(QIODevice::WriteOnly)) {
resumeFile.write(data);
if (!resumeFile.commit()) {
Logger::instance()->addMessage(QString("Couldn't save resume data in %1. Error: %2")
.arg(filepath).arg(resumeFile.errorString()), Log::WARNING);
}
}
}
void ResumeDataSavingManager::remove(const QString &filename) const
{
const QString filepath = m_resumeDataDir.absoluteFilePath(filename);
Utils::Fs::forceRemove(filepath);
}

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015, 2018 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015 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
@@ -26,7 +26,8 @@
* exception statement from your version.
*/
#pragma once
#ifndef RESUMEDATASAVINGMANAGER_H
#define RESUMEDATASAVINGMANAGER_H
#include <QByteArray>
#include <QDir>
@@ -35,15 +36,15 @@
class ResumeDataSavingManager : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(ResumeDataSavingManager)
public:
explicit ResumeDataSavingManager(const QString &resumeFolderPath);
public slots:
void save(const QString &filename, const QByteArray &data) const;
void remove(const QString &filename) const;
void saveResumeData(QString infoHash, QByteArray data) const;
private:
QDir m_resumeDataDir;
};
#endif // RESUMEDATASAVINGMANAGER_H

View File

@@ -22,7 +22,7 @@ Statistics::Statistics(Session *session)
, m_dirty(false)
{
load();
connect(&m_timer, &QTimer::timeout, this, &Statistics::gather);
connect(&m_timer, SIGNAL(timeout()), this, SLOT(gather()));
m_timer.start(60 * 1000);
}

View File

@@ -9,7 +9,7 @@ namespace BitTorrent
class Session;
}
class Statistics : public QObject
class Statistics : QObject
{
Q_OBJECT
Q_DISABLE_COPY(Statistics)
@@ -28,6 +28,7 @@ private:
void save() const;
void load();
private:
BitTorrent::Session *m_session;
// Will overflow at 15.9 EiB
quint64 m_alltimeUL;

File diff suppressed because it is too large Load Diff

View File

@@ -30,14 +30,18 @@
#ifndef BITTORRENT_SESSION_H
#define BITTORRENT_SESSION_H
#include <vector>
#include <libtorrent/version.hpp>
#include <vector>
#if LIBTORRENT_VERSION_NUM >= 10100
#include <QElapsedTimer>
#endif
#include <QFile>
#include <QHash>
#include <QList>
#include <QMap>
#if LIBTORRENT_VERSION_NUM < 10100
#include <QMutex>
#endif
#include <QNetworkConfigurationManager>
#include <QPointer>
#include <QSet>
@@ -45,12 +49,6 @@
#include <QVector>
#include <QWaitCondition>
#if LIBTORRENT_VERSION_NUM < 10100
#include <QMutex>
#else
#include <QElapsedTimer>
#endif
#include "base/settingvalue.h"
#include "base/tristatebool.h"
#include "base/types.h"
@@ -113,6 +111,7 @@ class QTimer;
class QStringList;
class QString;
class QUrl;
template<typename T> class QList;
class FilterParserThread;
class BandwidthScheduler;
@@ -138,7 +137,7 @@ namespace BitTorrent
class Tracker;
class MagnetUri;
class TrackerEntry;
struct CreateTorrentParams;
struct AddTorrentData;
struct TorrentStatusReport
{
@@ -237,7 +236,7 @@ namespace BitTorrent
int diskJobTime = 0;
} disk;
};
#endif // LIBTORRENT_VERSION_NUM >= 10100
#endif
class Session : public QObject
{
@@ -375,10 +374,6 @@ namespace BitTorrent
void setAnnounceToAllTrackers(bool val);
bool announceToAllTiers() const;
void setAnnounceToAllTiers(bool val);
int asyncIOThreads() const;
void setAsyncIOThreads(int num);
int checkingMemUsage() const;
void setCheckingMemUsage(int size);
int diskCacheSize() const;
void setDiskCacheSize(int size);
int diskCacheTTL() const;
@@ -387,8 +382,6 @@ namespace BitTorrent
void setUseOSCache(bool use);
bool isGuidedReadCacheEnabled() const;
void setGuidedReadCacheEnabled(bool enabled);
bool isCoalesceReadWriteEnabled() const;
void setCoalesceReadWriteEnabled(bool enabled);
bool isSuggestModeEnabled() const;
void setSuggestMode(bool mode);
int sendBufferWatermark() const;
@@ -403,12 +396,6 @@ namespace BitTorrent
void setQueueingSystemEnabled(bool enabled);
bool ignoreSlowTorrentsForQueueing() const;
void setIgnoreSlowTorrentsForQueueing(bool ignore);
int downloadRateForSlowTorrents() const;
void setDownloadRateForSlowTorrents(int rateInKibiBytes);
int uploadRateForSlowTorrents() const;
void setUploadRateForSlowTorrents(int rateInKibiBytes);
int slowTorrentsInactivityTimer() const;
void setSlowTorrentsInactivityTimer(int timeInSeconds);
int outgoingPortsMin() const;
void setOutgoingPortsMin(int min);
int outgoingPortsMax() const;
@@ -456,7 +443,6 @@ namespace BitTorrent
TorrentStatusReport torrentStatusReport() const;
bool hasActiveTorrents() const;
bool hasUnfinishedTorrents() const;
bool hasRunningSeed() const;
const SessionStatus &status() const;
const CacheStatus &cacheStatus() const;
quint64 getAlltimeDL() const;
@@ -482,9 +468,7 @@ namespace BitTorrent
void bottomTorrentsPriority(const QStringList &hashes);
// TorrentHandle interface
void handleTorrentSaveResumeDataRequested(TorrentHandle *const torrent);
void handleTorrentShareLimitChanged(TorrentHandle *const torrent);
void handleTorrentNameChanged(TorrentHandle *const torrent);
void handleTorrentSavePathChanged(TorrentHandle *const torrent);
void handleTorrentCategoryChanged(TorrentHandle *const torrent, const QString &oldCategory);
void handleTorrentTagAdded(TorrentHandle *const torrent, const QString &tag);
@@ -554,7 +538,7 @@ namespace BitTorrent
void generateResumeData(bool final = false);
void handleIPFilterParsed(int ruleCount);
void handleIPFilterError();
void handleDownloadFinished(const QString &url, const QByteArray &data);
void handleDownloadFinished(const QString &url, const QString &filePath);
void handleDownloadFailed(const QString &url, const QString &reason);
void handleRedirectedToMagnet(const QString &url, const QString &magnetUri);
@@ -570,7 +554,7 @@ namespace BitTorrent
bool requestedFileDeletion;
};
explicit Session(QObject *parent = nullptr);
explicit Session(QObject *parent = 0);
~Session();
bool hasPerTorrentRatioLimit() const;
@@ -602,20 +586,20 @@ namespace BitTorrent
void enableIPFilter();
void disableIPFilter();
bool addTorrent_impl(CreateTorrentParams params, const MagnetUri &magnetUri,
bool addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri,
TorrentInfo torrentInfo = TorrentInfo(),
const QByteArray &fastresumeData = QByteArray());
bool findIncompleteFiles(TorrentInfo &torrentInfo, QString &savePath) const;
void updateSeedingLimitTimer();
void exportTorrentFile(TorrentHandle *const torrent, TorrentExportFolder folder = TorrentExportFolder::Regular);
void saveTorrentResumeData(TorrentHandle *const torrent, bool finalSave = false);
void handleAlert(libtorrent::alert *a);
void dispatchTorrentAlert(libtorrent::alert *a);
void handleAddTorrentAlert(libtorrent::add_torrent_alert *p);
void handleStateUpdateAlert(libtorrent::state_update_alert *p);
void handleMetadataReceivedAlert(const libtorrent::metadata_received_alert *p);
void handleTorrentPausedAlert(const libtorrent::torrent_paused_alert *p);
void handleMetadataReceivedAlert(libtorrent::metadata_received_alert *p);
void handleFileErrorAlert(libtorrent::file_error_alert *p);
void handleTorrentRemovedAlert(libtorrent::torrent_removed_alert *p);
void handleTorrentDeletedAlert(libtorrent::torrent_deleted_alert *p);
@@ -635,8 +619,6 @@ namespace BitTorrent
void createTorrentHandle(const libtorrent::torrent_handle &nativeHandle);
void saveResumeData();
void saveTorrentsQueue();
void removeTorrentsQueue();
#if LIBTORRENT_VERSION_NUM < 10100
void dispatchAlerts(libtorrent::alert *alertPtr);
@@ -660,13 +642,10 @@ namespace BitTorrent
CachedSettingValue<QString> m_IPFilterFile;
CachedSettingValue<bool> m_announceToAllTrackers;
CachedSettingValue<bool> m_announceToAllTiers;
CachedSettingValue<int> m_asyncIOThreads;
CachedSettingValue<int> m_checkingMemUsage;
CachedSettingValue<int> m_diskCacheSize;
CachedSettingValue<int> m_diskCacheTTL;
CachedSettingValue<bool> m_useOSCache;
CachedSettingValue<bool> m_guidedReadCacheEnabled;
CachedSettingValue<bool> m_coalesceReadWriteEnabled;
CachedSettingValue<bool> m_isSuggestMode;
CachedSettingValue<int> m_sendBufferWatermark;
CachedSettingValue<int> m_sendBufferLowWatermark;
@@ -677,9 +656,6 @@ namespace BitTorrent
CachedSettingValue<int> m_maxActiveUploads;
CachedSettingValue<int> m_maxActiveTorrents;
CachedSettingValue<bool> m_ignoreSlowTorrentsForQueueing;
CachedSettingValue<int> m_downloadRateForSlowTorrents;
CachedSettingValue<int> m_uploadRateForSlowTorrents;
CachedSettingValue<int> m_slowTorrentsInactivityTimer;
CachedSettingValue<int> m_outgoingPortsMin;
CachedSettingValue<int> m_outgoingPortsMax;
CachedSettingValue<bool> m_ignoreLimitsOnLAN;
@@ -765,17 +741,13 @@ namespace BitTorrent
QHash<InfoHash, TorrentInfo> m_loadedMetadata;
QHash<InfoHash, TorrentHandle *> m_torrents;
QHash<InfoHash, CreateTorrentParams> m_addingTorrents;
QHash<InfoHash, AddTorrentData> m_addingTorrents;
QHash<QString, AddTorrentParams> m_downloadedTorrents;
QHash<InfoHash, RemovingTorrentData> m_removingTorrents;
TorrentStatusReport m_torrentStatusReport;
QStringMap m_categories;
QSet<QString> m_tags;
// I/O errored torrents
QSet<InfoHash> m_recentErroredTorrents;
QTimer *m_recentErroredTorrentsTimer;
#if LIBTORRENT_VERSION_NUM < 10100
QMutex m_alertsMutex;
QWaitCondition m_alertsWaitCondition;

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
* Copyright (C) 2010 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -24,6 +24,8 @@
* 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.
*
* Contact : chris@qbittorrent.org
*/
#include "torrentcreatorthread.h"
@@ -35,14 +37,9 @@
#include <libtorrent/create_torrent.hpp>
#include <libtorrent/storage.hpp>
#include <libtorrent/torrent_info.hpp>
#include <libtorrent/version.hpp>
#include <QDirIterator>
#include <QFile>
#include <QFileInfo>
#include <QHash>
#include "base/global.h"
#include "base/utils/fs.h"
#include "base/utils/misc.h"
#include "base/utils/string.h"
@@ -62,6 +59,8 @@ using namespace BitTorrent;
TorrentCreatorThread::TorrentCreatorThread(QObject *parent)
: QThread(parent)
, m_private(false)
, m_pieceSize(0)
{
}
@@ -71,149 +70,106 @@ TorrentCreatorThread::~TorrentCreatorThread()
wait();
}
void TorrentCreatorThread::create(const TorrentCreatorParams &params)
void TorrentCreatorThread::create(const QString &inputPath, const QString &savePath, const QStringList &trackers,
const QStringList &urlSeeds, const QString &comment, bool isPrivate, int pieceSize)
{
m_params = params;
m_inputPath = Utils::Fs::fromNativePath(inputPath);
m_savePath = Utils::Fs::fromNativePath(savePath);
if (QFile(m_savePath).exists())
Utils::Fs::forceRemove(m_savePath);
m_trackers = trackers;
m_urlSeeds = urlSeeds;
m_comment = comment;
m_private = isPrivate;
m_pieceSize = pieceSize;
start();
}
void TorrentCreatorThread::sendProgressSignal(int currentPieceIdx, int totalPieces)
void TorrentCreatorThread::sendProgressSignal(int numHashes, int numPieces)
{
emit updateProgress(static_cast<int>((currentPieceIdx * 100.) / totalPieces));
emit updateProgress(static_cast<int>((numHashes * 100.) / numPieces));
}
void TorrentCreatorThread::run()
{
const QString creatorStr("qBittorrent " QBT_VERSION);
emit updateProgress(0);
QString creator_str("qBittorrent " QBT_VERSION);
try {
const QString parentPath = Utils::Fs::branchPath(m_params.inputPath) + '/';
// Adding files to the torrent
libt::file_storage fs;
if (QFileInfo(m_params.inputPath).isFile()) {
libt::add_files(fs, Utils::Fs::toNativePath(m_params.inputPath).toStdString(), fileFilter);
}
else {
// need to sort the file names by natural sort order
QStringList dirs = {m_params.inputPath};
QDirIterator dirIter(m_params.inputPath, (QDir::AllDirs | QDir::NoDotAndDotDot), QDirIterator::Subdirectories);
while (dirIter.hasNext()) {
dirIter.next();
dirs += dirIter.filePath();
}
std::sort(dirs.begin(), dirs.end(), Utils::String::naturalLessThan<Qt::CaseInsensitive>);
QStringList fileNames;
QHash<QString, boost::int64_t> fileSizeMap;
for (const auto &dir : asConst(dirs)) {
QStringList tmpNames; // natural sort files within each dir
QDirIterator fileIter(dir, QDir::Files);
while (fileIter.hasNext()) {
fileIter.next();
const QString relFilePath = fileIter.filePath().mid(parentPath.length());
tmpNames += relFilePath;
fileSizeMap[relFilePath] = fileIter.fileInfo().size();
}
std::sort(tmpNames.begin(), tmpNames.end(), Utils::String::naturalLessThan<Qt::CaseInsensitive>);
fileNames += tmpNames;
}
for (const auto &fileName : asConst(fileNames))
fs.add_file(fileName.toStdString(), fileSizeMap[fileName]);
}
// Adding files to the torrent
libt::add_files(fs, Utils::Fs::toNativePath(m_inputPath).toStdString(), fileFilter);
if (isInterruptionRequested()) return;
#if LIBTORRENT_VERSION_NUM < 10100
libt::create_torrent newTorrent(fs, m_params.pieceSize, -1
, (m_params.isAlignmentOptimized ? libt::create_torrent::optimize : 0));
#else
libt::create_torrent newTorrent(fs, m_params.pieceSize, -1
, (m_params.isAlignmentOptimized ? libt::create_torrent::optimize_alignment : 0));
#endif
libt::create_torrent t(fs, m_pieceSize);
// Add url seeds
for (QString seed : asConst(m_params.urlSeeds)) {
seed = seed.trimmed();
if (!seed.isEmpty())
newTorrent.add_url_seed(seed.toStdString());
}
foreach (const QString &seed, m_urlSeeds)
t.add_url_seed(seed.trimmed().toStdString());
int tier = 0;
for (const QString &tracker : asConst(m_params.trackers)) {
if (tracker.isEmpty())
bool newline = false;
foreach (const QString &tracker, m_trackers) {
if (tracker.isEmpty()) {
if (newline)
continue;
++tier;
else
newTorrent.add_tracker(tracker.trimmed().toStdString(), tier);
newline = true;
continue;
}
t.add_tracker(tracker.trimmed().toStdString(), tier);
newline = false;
}
if (isInterruptionRequested()) return;
// calculate the hash for all pieces
libt::set_piece_hashes(newTorrent, Utils::Fs::toNativePath(parentPath).toStdString()
, [this, &newTorrent](const int n) { sendProgressSignal(n, newTorrent.num_pieces()); });
const QString parentPath = Utils::Fs::branchPath(m_inputPath) + "/";
libt::set_piece_hashes(t, Utils::Fs::toNativePath(parentPath).toStdString(), boost::bind(&TorrentCreatorThread::sendProgressSignal, this, _1, t.num_pieces()));
// Set qBittorrent as creator and add user comment to
// torrent_info structure
newTorrent.set_creator(creatorStr.toUtf8().constData());
newTorrent.set_comment(m_params.comment.toUtf8().constData());
t.set_creator(creator_str.toUtf8().constData());
t.set_comment(m_comment.toUtf8().constData());
// Is private ?
newTorrent.set_priv(m_params.isPrivate);
t.set_priv(m_private);
if (isInterruptionRequested()) return;
libt::entry entry = newTorrent.generate();
// add source field
if (!m_params.source.isEmpty())
entry["info"]["source"] = m_params.source.toStdString();
if (isInterruptionRequested()) return;
// create the torrent
std::ofstream outfile(
// create the torrent and print it to out
qDebug("Saving to %s", qUtf8Printable(m_savePath));
#ifdef _MSC_VER
Utils::Fs::toNativePath(m_params.savePath).toStdWString().c_str()
wchar_t *savePathW = new wchar_t[m_savePath.length() + 1];
int len = Utils::Fs::toNativePath(m_savePath).toWCharArray(savePathW);
savePathW[len] = L'\0';
std::ofstream outfile(savePathW, std::ios_base::out | std::ios_base::binary);
delete[] savePathW;
#else
Utils::Fs::toNativePath(m_params.savePath).toUtf8().constData()
std::ofstream outfile(Utils::Fs::toNativePath(m_savePath).toLocal8Bit().constData(), std::ios_base::out | std::ios_base::binary);
#endif
, (std::ios_base::out | std::ios_base::binary | std::ios_base::trunc));
if (outfile.fail())
throw std::runtime_error(tr("create new torrent file failed").toStdString());
throw std::exception();
if (isInterruptionRequested()) return;
libt::bencode(std::ostream_iterator<char>(outfile), entry);
libt::bencode(std::ostream_iterator<char>(outfile), t.generate());
outfile.close();
emit updateProgress(100);
emit creationSuccess(m_params.savePath, parentPath);
emit creationSuccess(m_savePath, parentPath);
}
catch (const std::exception &e) {
emit creationFailure(e.what());
catch (std::exception& e) {
emit creationFailure(QString::fromStdString(e.what()));
}
}
int TorrentCreatorThread::calculateTotalPieces(const QString &inputPath, const int pieceSize, const bool isAlignmentOptimized)
int TorrentCreatorThread::calculateTotalPieces(const QString &inputPath, const int pieceSize)
{
if (inputPath.isEmpty())
return 0;
libt::file_storage fs;
libt::add_files(fs, Utils::Fs::toNativePath(inputPath).toStdString(), fileFilter);
#if LIBTORRENT_VERSION_NUM < 10100
return libt::create_torrent(fs, pieceSize, -1
, (isAlignmentOptimized ? libt::create_torrent::optimize : 0)).num_pieces();
#else
return libt::create_torrent(fs, pieceSize, -1
, (isAlignmentOptimized ? libt::create_torrent::optimize_alignment : 0)).num_pieces();
#endif
return libt::create_torrent(fs, pieceSize).num_pieces();
}

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
* Copyright (C) 2010 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -24,6 +24,8 @@
* 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.
*
* Contact : chris@qbittorrent.org
*/
#ifndef BITTORRENT_TORRENTCREATORTHREAD_H
@@ -34,30 +36,18 @@
namespace BitTorrent
{
struct TorrentCreatorParams
{
bool isPrivate;
bool isAlignmentOptimized;
int pieceSize;
QString inputPath;
QString savePath;
QString comment;
QString source;
QStringList trackers;
QStringList urlSeeds;
};
class TorrentCreatorThread : public QThread
{
Q_OBJECT
public:
TorrentCreatorThread(QObject *parent = nullptr);
TorrentCreatorThread(QObject *parent = 0);
~TorrentCreatorThread();
void create(const TorrentCreatorParams &params);
void create(const QString &inputPath, const QString &savePath, const QStringList &trackers,
const QStringList &urlSeeds, const QString &comment, bool isPrivate, int pieceSize);
static int calculateTotalPieces(const QString &inputPath, const int pieceSize, const bool isAlignmentOptimized);
static int calculateTotalPieces(const QString &inputPath, const int pieceSize);
protected:
void run();
@@ -68,9 +58,15 @@ namespace BitTorrent
void updateProgress(int progress);
private:
void sendProgressSignal(int currentPieceIdx, int totalPieces);
void sendProgressSignal(int numHashes, int numPieces);
TorrentCreatorParams m_params;
QString m_inputPath;
QString m_savePath;
QStringList m_trackers;
QStringList m_urlSeeds;
QString m_comment;
bool m_private;
int m_pieceSize;
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -88,10 +88,10 @@ namespace BitTorrent
class TrackerEntry;
struct AddTorrentParams;
struct CreateTorrentParams
struct AddTorrentData
{
bool restored; // is existing torrent job?
// for both new and restored torrents
bool resumed;
// for both new and resumed torrents
QString name;
QString category;
QSet<QString> tags;
@@ -102,18 +102,18 @@ namespace BitTorrent
bool hasSeedStatus;
bool skipChecking;
bool hasRootFolder;
bool forced;
bool paused;
bool addForced;
bool addPaused;
int uploadLimit;
int downloadLimit;
// for new torrents
QVector<int> filePriorities;
// for restored torrents
// for resumed torrents
qreal ratioLimit;
int seedingTimeLimit;
CreateTorrentParams();
CreateTorrentParams(const AddTorrentParams &params);
AddTorrentData();
AddTorrentData(const AddTorrentParams &params);
};
struct TrackerInfo
@@ -149,8 +149,6 @@ namespace BitTorrent
PausedDownloading,
PausedUploading,
Moving,
MissingFiles,
Error
};
@@ -158,7 +156,6 @@ namespace BitTorrent
class TorrentHandle : public QObject
{
Q_DISABLE_COPY(TorrentHandle)
Q_DECLARE_TR_FUNCTIONS(BitTorrent::TorrentHandle)
public:
static const qreal USE_GLOBAL_RATIO;
@@ -171,7 +168,7 @@ namespace BitTorrent
static const int MAX_SEEDING_TIME;
TorrentHandle(Session *session, const libtorrent::torrent_handle &nativeHandle,
const CreateTorrentParams &params);
const AddTorrentData &data);
~TorrentHandle();
bool isValid() const;
@@ -334,7 +331,7 @@ namespace BitTorrent
void setName(const QString &name);
void setSequentialDownload(bool b);
void toggleSequentialDownload();
void setFirstLastPiecePriority(bool enabled);
void setFirstLastPiecePriority(bool b);
void toggleFirstLastPiecePriority();
void pause();
void resume(bool forced = false);
@@ -348,6 +345,7 @@ namespace BitTorrent
void renameFile(int index, const QString &name);
bool saveTorrentFile(const QString &path);
void prioritizeFiles(const QVector<int> &priorities);
void setFilePriority(int index, int priority);
void setRatioLimit(qreal limit);
void setSeedingTimeLimit(int limit);
void setUploadLimit(int limit);
@@ -355,7 +353,7 @@ namespace BitTorrent
void setSuperSeeding(bool enable);
void flushCache();
void addTrackers(const QList<TrackerEntry> &trackers);
void replaceTrackers(const QList<TrackerEntry> &trackers);
void replaceTrackers(QList<TrackerEntry> trackers);
void addUrlSeeds(const QList<QUrl> &urlSeeds);
void removeUrlSeeds(const QList<QUrl> &urlSeeds);
bool connectPeer(const PeerAddress &peerAddress);
@@ -372,7 +370,7 @@ namespace BitTorrent
void handleTempPathChanged();
void handleCategorySavePathChanged();
void handleAppendExtensionToggled();
void saveResumeData();
void saveResumeData(bool updateStatus = false);
/**
* @brief fraction of file pieces that are available at least from one peer
@@ -385,36 +383,29 @@ namespace BitTorrent
private:
typedef boost::function<void ()> EventTrigger;
#if (LIBTORRENT_VERSION_NUM < 10200)
using LTFileIndex = int;
#else
using LTFileIndex = lt::file_index_t;
#endif
void updateStatus();
void updateStatus(const libtorrent::torrent_status &nativeStatus);
void updateState();
void updateTorrentInfo();
void handleStorageMovedAlert(const libtorrent::storage_moved_alert *p);
void handleStorageMovedFailedAlert(const libtorrent::storage_moved_failed_alert *p);
void handleTrackerReplyAlert(const libtorrent::tracker_reply_alert *p);
void handleTrackerWarningAlert(const libtorrent::tracker_warning_alert *p);
void handleTrackerErrorAlert(const libtorrent::tracker_error_alert *p);
void handleTorrentCheckedAlert(const libtorrent::torrent_checked_alert *p);
void handleTorrentFinishedAlert(const libtorrent::torrent_finished_alert *p);
void handleTorrentPausedAlert(const libtorrent::torrent_paused_alert *p);
void handleTorrentResumedAlert(const libtorrent::torrent_resumed_alert *p);
void handleSaveResumeDataAlert(const libtorrent::save_resume_data_alert *p);
void handleSaveResumeDataFailedAlert(const libtorrent::save_resume_data_failed_alert *p);
void handleFastResumeRejectedAlert(const libtorrent::fastresume_rejected_alert *p);
void handleFileRenamedAlert(const libtorrent::file_renamed_alert *p);
void handleFileRenameFailedAlert(const libtorrent::file_rename_failed_alert *p);
void handleFileCompletedAlert(const libtorrent::file_completed_alert *p);
void handleMetadataReceivedAlert(const libtorrent::metadata_received_alert *p);
void handleStatsAlert(const libtorrent::stats_alert *p);
void handleStorageMovedAlert(libtorrent::storage_moved_alert *p);
void handleStorageMovedFailedAlert(libtorrent::storage_moved_failed_alert *p);
void handleTrackerReplyAlert(libtorrent::tracker_reply_alert *p);
void handleTrackerWarningAlert(libtorrent::tracker_warning_alert *p);
void handleTrackerErrorAlert(libtorrent::tracker_error_alert *p);
void handleTorrentCheckedAlert(libtorrent::torrent_checked_alert *p);
void handleTorrentFinishedAlert(libtorrent::torrent_finished_alert *p);
void handleTorrentPausedAlert(libtorrent::torrent_paused_alert *p);
void handleTorrentResumedAlert(libtorrent::torrent_resumed_alert *p);
void handleSaveResumeDataAlert(libtorrent::save_resume_data_alert *p);
void handleSaveResumeDataFailedAlert(libtorrent::save_resume_data_failed_alert *p);
void handleFastResumeRejectedAlert(libtorrent::fastresume_rejected_alert *p);
void handleFileRenamedAlert(libtorrent::file_renamed_alert *p);
void handleFileRenameFailedAlert(libtorrent::file_rename_failed_alert *p);
void handleFileCompletedAlert(libtorrent::file_completed_alert *p);
void handleMetadataReceivedAlert(libtorrent::metadata_received_alert *p);
void handleStatsAlert(libtorrent::stats_alert *p);
void resume_impl(bool forced);
bool isMoveInProgress() const;
QString nativeActualSavePath() const;
@@ -426,7 +417,6 @@ namespace BitTorrent
bool addTracker(const TrackerEntry &tracker);
bool addUrlSeed(const QUrl &urlSeed);
bool removeUrlSeed(const QUrl &urlSeed);
void setFirstLastPiecePriorityImpl(bool enabled, const QVector<int> &updatedFilePrio = {});
Session *const m_session;
libtorrent::torrent_handle m_nativeHandle;
@@ -452,10 +442,6 @@ namespace BitTorrent
QQueue<EventTrigger> m_moveFinishedTriggers;
int m_renameCount;
// Until libtorrent provide an "old_name" field in `file_renamed_alert`
// we will rely on this workaround to remove empty leftover folders
QHash<LTFileIndex, QVector<QString>> m_oldPath;
bool m_useAutoTMM;
// Persistent data
@@ -467,26 +453,13 @@ namespace BitTorrent
qreal m_ratioLimit;
int m_seedingTimeLimit;
bool m_tempPathDisabled;
bool m_fastresumeDataRejected;
bool m_hasMissingFiles;
bool m_hasRootFolder;
bool m_needsToSetFirstLastPiecePriority;
bool m_needsToStartForced;
bool m_pauseAfterRecheck;
bool m_needSaveResumeData;
QHash<QString, TrackerInfo> m_trackerInfos;
enum StartupState
{
Preparing, // torrent is preparing to start regular processing
Starting, // torrent is prepared and starting to perform regular processing
Started // torrent is performing regular processing
};
StartupState m_startupState = Preparing;
// Handle torrent state when it starts performing some service job
// being in Paused state so it might be unpaused internally and then paused again
bool m_pauseWhenReady;
bool m_unchecked = false;
};
}

View File

@@ -26,21 +26,20 @@
* exception statement from your version.
*/
#include "torrentinfo.h"
#include <QDebug>
#include <QString>
#include <QList>
#include <QUrl>
#include <QDateTime>
#include <libtorrent/error_code.hpp>
#include <QDateTime>
#include <QDebug>
#include <QString>
#include <QUrl>
#include "base/global.h"
#include "base/utils/fs.h"
#include "base/utils/misc.h"
#include "base/utils/fs.h"
#include "base/utils/string.h"
#include "infohash.h"
#include "trackerentry.h"
#include "torrentinfo.h"
namespace libt = libtorrent;
using namespace BitTorrent;
@@ -61,75 +60,23 @@ TorrentInfo &TorrentInfo::operator=(const TorrentInfo &other)
return *this;
}
TorrentInfo TorrentInfo::load(const QByteArray &data, QString *error) noexcept
TorrentInfo TorrentInfo::loadFromFile(const QString &path, QString &error)
{
// 2-step construction to overcome default limits of `depth_limit` & `token_limit` which are
// used in `torrent_info()` constructor
const int depthLimit = 100;
const int tokenLimit = 10000000;
error.clear();
libt::error_code ec;
#if LIBTORRENT_VERSION_NUM < 10100
libt::lazy_entry node;
libt::lazy_bdecode(data.constData(), (data.constData() + data.size()), node, ec
, nullptr, depthLimit, tokenLimit);
#else
libt::bdecode_node node;
bdecode(data.constData(), (data.constData() + data.size()), node, ec
, nullptr, depthLimit, tokenLimit);
#endif
TorrentInfo info(NativePtr(new libt::torrent_info(Utils::Fs::toNativePath(path).toStdString(), ec)));
if (ec) {
if (error)
*error = QString::fromStdString(ec.message());
return TorrentInfo();
}
TorrentInfo info {NativePtr(new libt::torrent_info(node, ec))};
if (ec) {
if (error)
*error = QString::fromStdString(ec.message());
return TorrentInfo();
error = QString::fromUtf8(ec.message().c_str());
qDebug("Cannot load .torrent file: %s", qUtf8Printable(error));
}
return info;
}
TorrentInfo TorrentInfo::loadFromFile(const QString &path, QString *error) noexcept
TorrentInfo TorrentInfo::loadFromFile(const QString &path)
{
if (error)
error->clear();
QFile file {path};
if (!file.open(QIODevice::ReadOnly)) {
if (error)
*error = file.errorString();
return TorrentInfo();
}
if (file.size() > MAX_TORRENT_SIZE) {
if (error)
*error = tr("File size exceeds max limit %1").arg(Utils::Misc::friendlyUnit(MAX_TORRENT_SIZE));
return TorrentInfo();
}
QByteArray data;
try {
data = file.readAll();
}
catch (const std::bad_alloc &e) {
if (error)
*error = tr("Torrent file read error: %1").arg(e.what());
return TorrentInfo();
}
if (data.size() != file.size()) {
if (error)
*error = tr("Torrent file read error: size mismatch");
return TorrentInfo();
}
file.close();
return load(data, error);
QString error;
return loadFromFile(path, error);
}
bool TorrentInfo::isValid() const
@@ -247,7 +194,7 @@ QList<TrackerEntry> TorrentInfo::trackers() const
if (!isValid()) return QList<TrackerEntry>();
QList<TrackerEntry> trackers;
for (const libt::announce_entry &tracker : m_nativeInfo->trackers())
foreach (const libt::announce_entry &tracker, m_nativeInfo->trackers())
trackers.append(tracker);
return trackers;
@@ -258,7 +205,7 @@ QList<QUrl> TorrentInfo::urlSeeds() const
if (!isValid()) return QList<QUrl>();
QList<QUrl> urlSeeds;
for (const libt::web_seed_entry &webSeed : m_nativeInfo->web_seeds())
foreach (const libt::web_seed_entry &webSeed, m_nativeInfo->web_seeds())
if (webSeed.type == libt::web_seed_entry::url_seed)
urlSeeds.append(QUrl(webSeed.url.c_str()));
@@ -314,7 +261,7 @@ QVector<QByteArray> TorrentInfo::pieceHashes() const
return hashes;
}
TorrentInfo::PieceRange TorrentInfo::filePieces(const QString &file) const
TorrentInfo::PieceRange TorrentInfo::filePieces(const QString& file) const
{
if (!isValid()) // if we do not check here the debug message will be printed, which would be not correct
return {};
@@ -339,26 +286,21 @@ TorrentInfo::PieceRange TorrentInfo::filePieces(int fileIndex) const
const libt::file_storage &files = nativeInfo()->files();
const auto fileSize = files.file_size(fileIndex);
const auto fileOffset = files.file_offset(fileIndex);
const int beginIdx = (fileOffset / pieceLength());
const int endIdx = ((fileOffset + fileSize - 1) / pieceLength());
if (fileSize <= 0)
return {beginIdx, 0};
return makeInterval(beginIdx, endIdx);
const auto firstOffset = files.file_offset(fileIndex);
return makeInterval(static_cast<int>(firstOffset / pieceLength()),
static_cast<int>((firstOffset + fileSize - 1) / pieceLength()));
}
void TorrentInfo::renameFile(const int index, const QString &newPath)
void TorrentInfo::renameFile(uint index, const QString &newPath)
{
if (!isValid()) return;
nativeInfo()->rename_file(index, Utils::Fs::toNativePath(newPath).toStdString());
}
int BitTorrent::TorrentInfo::fileIndex(const QString &fileName) const
int BitTorrent::TorrentInfo::fileIndex(const QString& fileName) const
{
// the check whether the object is valid is not needed here
// because if filesCount() returns -1 the loop exits immediately
// the check whether the object valid is not needed here
// because filesCount() returns -1 in that case and the loop exits immediately
for (int i = 0; i < filesCount(); ++i)
if (fileName == filePath(i))
return i;
@@ -366,29 +308,24 @@ int BitTorrent::TorrentInfo::fileIndex(const QString &fileName) const
return -1;
}
QString TorrentInfo::rootFolder() const
bool TorrentInfo::hasRootFolder() const
{
QString rootFolder;
QString testRootFolder;
for (int i = 0; i < filesCount(); ++i) {
const QString filePath = this->filePath(i);
if (QDir::isAbsolutePath(filePath)) continue;
const auto filePathElements = filePath.splitRef('/');
// if at least one file has no root folder, no common root folder exists
if (filePathElements.count() <= 1) return "";
if (filePathElements.count() <= 1) return false;
if (rootFolder.isEmpty())
rootFolder = filePathElements.at(0).toString();
else if (rootFolder != filePathElements.at(0))
return "";
if (testRootFolder.isEmpty())
testRootFolder = filePathElements.at(0).toString();
else if (testRootFolder != filePathElements.at(0))
return false;
}
return rootFolder;
}
bool TorrentInfo::hasRootFolder() const
{
return !rootFolder().isEmpty();
return true;
}
void TorrentInfo::stripRootFolder()

View File

@@ -29,21 +29,20 @@
#ifndef BITTORRENT_TORRENTINFO_H
#define BITTORRENT_TORRENTINFO_H
#include <QtGlobal>
#include <libtorrent/torrent_info.hpp>
#include <libtorrent/version.hpp>
#include <QCoreApplication>
#include <QList>
#include <QtGlobal>
#include <QVector>
#include "base/indexrange.h"
class QByteArray;
class QDateTime;
class QString;
class QStringList;
class QUrl;
class QDateTime;
class QStringList;
class QByteArray;
template<typename T> class QList;
template<typename T> class QVector;
namespace BitTorrent
{
@@ -52,8 +51,6 @@ namespace BitTorrent
class TorrentInfo
{
Q_DECLARE_TR_FUNCTIONS(TorrentInfo)
public:
#if LIBTORRENT_VERSION_NUM < 10100
typedef boost::intrusive_ptr<const libtorrent::torrent_info> NativeConstPtr;
@@ -66,8 +63,8 @@ namespace BitTorrent
explicit TorrentInfo(NativeConstPtr nativeInfo = NativeConstPtr());
TorrentInfo(const TorrentInfo &other);
static TorrentInfo load(const QByteArray &data, QString *error = nullptr) noexcept;
static TorrentInfo loadFromFile(const QString &path, QString *error = nullptr) noexcept;
static TorrentInfo loadFromFile(const QString &path, QString &error);
static TorrentInfo loadFromFile(const QString &path);
TorrentInfo &operator=(const TorrentInfo &other);
@@ -102,9 +99,8 @@ namespace BitTorrent
PieceRange filePieces(const QString &file) const;
PieceRange filePieces(int fileIndex) const;
void renameFile(int index, const QString &newPath);
void renameFile(uint index, const QString &newPath);
QString rootFolder() const;
bool hasRootFolder() const;
void stripRootFolder();

View File

@@ -1,5 +1,5 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
@@ -27,13 +27,15 @@
* exception statement from your version.
*/
#include "tracker.h"
#include <vector>
#include <libtorrent/bencode.hpp>
#include <libtorrent/entry.hpp>
#include "base/http/server.h"
#include "base/preferences.h"
#include "base/utils/string.h"
#include "tracker.h"
// static limits
static const int MAX_TORRENTS = 100;
@@ -55,7 +57,7 @@ bool Peer::operator==(const Peer &other) const
QString Peer::uid() const
{
return ip.toString() + ':' + QString::number(port);
return ip + ":" + QString::number(port);
}
libtorrent::entry Peer::toEntry(bool noPeerId) const
@@ -63,7 +65,7 @@ libtorrent::entry Peer::toEntry(bool noPeerId) const
libtorrent::entry::dictionary_type peerMap;
if (!noPeerId)
peerMap["id"] = libtorrent::entry(peerId.toStdString());
peerMap["ip"] = libtorrent::entry(ip.toString().toStdString());
peerMap["ip"] = libtorrent::entry(ip.toStdString());
peerMap["port"] = libtorrent::entry(port);
return libtorrent::entry(peerMap);
@@ -72,7 +74,7 @@ libtorrent::entry Peer::toEntry(bool noPeerId) const
// Tracker
Tracker::Tracker(QObject *parent)
: QObject(parent)
: Http::ResponseBuilder(parent)
, m_server(new Http::Server(this, this))
{
}
@@ -128,21 +130,19 @@ Http::Response Tracker::processRequest(const Http::Request &request, const Http:
void Tracker::respondToAnnounceRequest()
{
const QMap<QString, QByteArray> &queryParams = m_request.query;
TrackerAnnounceRequest announceReq;
const QStringMap &gets = m_request.gets;
TrackerAnnounceRequest annonceReq;
// IP
// Use the "ip" parameter provided from tracker request first, then fall back to client IP if invalid
const QHostAddress paramIP {QString::fromLatin1(queryParams.value("ip"))};
announceReq.peer.ip = paramIP.isNull() ? m_env.clientAddress : paramIP;
annonceReq.peer.ip = m_env.clientAddress.toString();
// 1. Get info_hash
if (!queryParams.contains("info_hash")) {
if (!gets.contains("info_hash")) {
qDebug("Tracker: Missing info_hash");
status(101, "Missing info_hash");
return;
}
announceReq.infoHash = queryParams.value("info_hash");
annonceReq.infoHash = gets.value("info_hash");
// info_hash cannot be longer than 20 bytes
/*if (annonce_req.info_hash.toLatin1().length() > 20) {
qDebug("Tracker: Info_hash is not 20 byte long: %s (%d)", qUtf8Printable(annonce_req.info_hash), annonce_req.info_hash.toLatin1().length());
@@ -151,12 +151,12 @@ void Tracker::respondToAnnounceRequest()
}*/
// 2. Get peer ID
if (!queryParams.contains("peer_id")) {
if (!gets.contains("peer_id")) {
qDebug("Tracker: Missing peer_id");
status(102, "Missing peer_id");
return;
}
announceReq.peer.peerId = queryParams.value("peer_id");
annonceReq.peer.peerId = gets.value("peer_id");
// peer_id cannot be longer than 20 bytes
/*if (annonce_req.peer.peer_id.length() > 20) {
qDebug("Tracker: peer_id is not 20 byte long: %s", qUtf8Printable(annonce_req.peer.peer_id));
@@ -165,102 +165,92 @@ void Tracker::respondToAnnounceRequest()
}*/
// 3. Get port
if (!queryParams.contains("port")) {
if (!gets.contains("port")) {
qDebug("Tracker: Missing port");
status(103, "Missing port");
return;
}
bool ok = false;
announceReq.peer.port = queryParams.value("port").toInt(&ok);
if (!ok || (announceReq.peer.port < 0) || (announceReq.peer.port > 65535)) {
qDebug("Tracker: Invalid port number (%d)", announceReq.peer.port);
annonceReq.peer.port = gets.value("port").toInt(&ok);
if (!ok || annonceReq.peer.port < 1 || annonceReq.peer.port > 65535) {
qDebug("Tracker: Invalid port number (%d)", annonceReq.peer.port);
status(103, "Missing port");
return;
}
// 4. Get event
announceReq.event = "";
if (queryParams.contains("event")) {
announceReq.event = queryParams.value("event");
qDebug("Tracker: event is %s", qUtf8Printable(announceReq.event));
annonceReq.event = "";
if (gets.contains("event")) {
annonceReq.event = gets.value("event");
qDebug("Tracker: event is %s", qUtf8Printable(annonceReq.event));
}
// 5. Get numwant
announceReq.numwant = 50;
if (queryParams.contains("numwant")) {
int tmp = queryParams.value("numwant").toInt();
annonceReq.numwant = 50;
if (gets.contains("numwant")) {
int tmp = gets.value("numwant").toInt();
if (tmp > 0) {
qDebug("Tracker: numwant = %d", tmp);
announceReq.numwant = tmp;
annonceReq.numwant = tmp;
}
}
// 6. no_peer_id (extension)
announceReq.noPeerId = false;
if (queryParams.contains("no_peer_id"))
announceReq.noPeerId = true;
annonceReq.noPeerId = false;
if (gets.contains("no_peer_id"))
annonceReq.noPeerId = true;
// 7. TODO: support "compact" extension
// Done parsing, now let's reply
if (announceReq.event == "stopped") {
unregisterPeer(announceReq);
if (m_torrents.contains(annonceReq.infoHash)) {
if (annonceReq.event == "stopped") {
qDebug("Tracker: Peer stopped downloading, deleting it from the list");
m_torrents[annonceReq.infoHash].remove(annonceReq.peer.uid());
return;
}
}
else {
registerPeer(announceReq);
replyWithPeerList(announceReq);
}
}
void Tracker::registerPeer(const TrackerAnnounceRequest &announceReq)
{
if (announceReq.peer.port == 0) return;
if (!m_torrents.contains(announceReq.infoHash)) {
// Unknown torrent
if (m_torrents.size() == MAX_TORRENTS) {
// Reached max size, remove a random torrent
m_torrents.erase(m_torrents.begin());
}
}
// Register the user
PeerList &peers = m_torrents[announceReq.infoHash];
if (!peers.contains(announceReq.peer.uid())) {
// Unknown peer
if (peers.size() == MAX_PEERS_PER_TORRENT) {
// Too many peers, remove a random one
peers.erase(peers.begin());
}
PeerList peers = m_torrents.value(annonceReq.infoHash);
if (peers.size() == MAX_PEERS_PER_TORRENT) {
// Too many peers, remove a random one
peers.erase(peers.begin());
}
peers[announceReq.peer.uid()] = announceReq.peer;
peers[annonceReq.peer.uid()] = annonceReq.peer;
m_torrents[annonceReq.infoHash] = peers;
// Reply
replyWithPeerList(annonceReq);
}
void Tracker::unregisterPeer(const TrackerAnnounceRequest &announceReq)
{
if (announceReq.peer.port == 0) return;
if (m_torrents[announceReq.infoHash].remove(announceReq.peer.uid()) > 0)
qDebug("Tracker: Peer stopped downloading, deleting it from the list");
}
void Tracker::replyWithPeerList(const TrackerAnnounceRequest &announceReq)
void Tracker::replyWithPeerList(const TrackerAnnounceRequest &annonceReq)
{
// Prepare the entry for bencoding
libtorrent::entry::dictionary_type replyDict;
replyDict["interval"] = libtorrent::entry(ANNOUNCE_INTERVAL);
QList<Peer> peers = m_torrents.value(annonceReq.infoHash).values();
libtorrent::entry::list_type peerList;
for (const Peer &p : m_torrents.value(announceReq.infoHash))
peerList.push_back(p.toEntry(announceReq.noPeerId));
foreach (const Peer &p, peers) {
//if (p != annonce_req.peer)
peerList.push_back(p.toEntry(annonceReq.noPeerId));
}
replyDict["peers"] = libtorrent::entry(peerList);
const libtorrent::entry replyEntry(replyDict);
libtorrent::entry replyEntry(replyDict);
// bencode
QByteArray reply;
libtorrent::bencode(std::back_inserter(reply), replyEntry);
std::vector<char> buf;
libtorrent::bencode(std::back_inserter(buf), replyEntry);
QByteArray reply(&buf[0], static_cast<int>(buf.size()));
qDebug("Tracker: reply with the following bencoded data:\n %s", reply.constData());
// HTTP reply
print(reply, Http::CONTENT_TYPE_TXT);
}

View File

@@ -31,11 +31,10 @@
#define BITTORRENT_TRACKER_H
#include <QHash>
#include <QObject>
#include <QHostAddress>
#include "base/http/irequesthandler.h"
#include "base/http/responsebuilder.h"
#include "base/http/types.h"
namespace libtorrent
{
@@ -51,8 +50,8 @@ namespace BitTorrent
{
struct Peer
{
QHostAddress ip;
QByteArray peerId;
QString ip;
QString peerId;
int port;
bool operator!=(const Peer &other) const;
@@ -63,7 +62,7 @@ namespace BitTorrent
struct TrackerAnnounceRequest
{
QByteArray infoHash;
QString infoHash;
QString event;
int numwant;
Peer peer;
@@ -72,11 +71,11 @@ namespace BitTorrent
};
typedef QHash<QString, Peer> PeerList;
typedef QHash<QByteArray, PeerList> TorrentList;
typedef QHash<QString, PeerList> TorrentList;
/* Basic Bittorrent tracker implementation in Qt */
/* Following http://wiki.theory.org/BitTorrent_Tracker_Protocol */
class Tracker : public QObject, public Http::IRequestHandler, private Http::ResponseBuilder
class Tracker : public Http::ResponseBuilder, public Http::IRequestHandler
{
Q_OBJECT
Q_DISABLE_COPY(Tracker)
@@ -90,9 +89,7 @@ namespace BitTorrent
private:
void respondToAnnounceRequest();
void registerPeer(const TrackerAnnounceRequest &announceReq);
void unregisterPeer(const TrackerAnnounceRequest &announceReq);
void replyWithPeerList(const TrackerAnnounceRequest &announceReq);
void replyWithPeerList(const TrackerAnnounceRequest &annonceReq);
Http::Server *m_server;
TorrentList m_torrents;

View File

@@ -26,12 +26,11 @@
* exception statement from your version.
*/
#include "trackerentry.h"
#include <QString>
#include "base/utils/misc.h"
#include "base/utils/string.h"
#include "trackerentry.h"
using namespace BitTorrent;

View File

@@ -44,10 +44,10 @@ namespace BitTorrent
public:
enum Status
{
NotContacted = 1,
Working = 2,
Updating = 3,
NotWorking = 4
NotContacted,
Working,
Updating,
NotWorking
};
TrackerEntry(const QString &url);

View File

@@ -1,39 +0,0 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018 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 "exceptions.h"
RuntimeError::RuntimeError(const QString &message)
: std::runtime_error {message.toUtf8().data()}
{
}
QString RuntimeError::message() const
{
return what();
}

View File

@@ -1,120 +1,143 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018
*
* 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 "filesystemwatcher.h"
#include <QtGlobal>
#if defined(Q_OS_MAC) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
#include <cstring>
#include <sys/mount.h>
#ifndef Q_OS_WIN
#include <QSet>
#include <iostream>
#include <errno.h>
#if defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)
#include <sys/param.h>
#include <sys/mount.h>
#include <string.h>
#elif !defined Q_OS_HAIKU
#include <sys/vfs.h>
#endif
#endif
#include "base/algorithm.h"
#include "base/bittorrent/magneturi.h"
#include "base/bittorrent/torrentinfo.h"
#include "base/global.h"
#include "base/logger.h"
#include "base/preferences.h"
#include "base/utils/fs.h"
#include "filesystemwatcher.h"
namespace
{
const int WATCH_INTERVAL = 10000; // 10 sec
const int MAX_PARTIAL_RETRIES = 5;
}
#ifndef CIFS_MAGIC_NUMBER
#define CIFS_MAGIC_NUMBER 0xFF534D42
#endif
#ifndef NFS_SUPER_MAGIC
#define NFS_SUPER_MAGIC 0x6969
#endif
#ifndef SMB_SUPER_MAGIC
#define SMB_SUPER_MAGIC 0x517B
#endif
const int WATCH_INTERVAL = 10000; // 10 sec
const int MAX_PARTIAL_RETRIES = 5;
FileSystemWatcher::FileSystemWatcher(QObject *parent)
: QFileSystemWatcher(parent)
{
connect(this, &QFileSystemWatcher::directoryChanged, this, &FileSystemWatcher::scanLocalFolder);
m_filters << "*.torrent" << "*.magnet";
connect(this, SIGNAL(directoryChanged(QString)), SLOT(scanLocalFolder(QString)));
}
m_partialTorrentTimer.setSingleShot(true);
connect(&m_partialTorrentTimer, &QTimer::timeout, this, &FileSystemWatcher::processPartialTorrents);
connect(&m_watchTimer, &QTimer::timeout, this, &FileSystemWatcher::scanNetworkFolders);
FileSystemWatcher::~FileSystemWatcher()
{
#ifndef Q_OS_WIN
if (m_watchTimer)
delete m_watchTimer;
#endif
if (m_partialTorrentTimer)
delete m_partialTorrentTimer;
}
QStringList FileSystemWatcher::directories() const
{
QStringList dirs = QFileSystemWatcher::directories();
for (const QDir &dir : asConst(m_watchedFolders))
dirs << dir.canonicalPath();
QStringList dirs;
#ifndef Q_OS_WIN
if (m_watchTimer) {
foreach (const QDir &dir, m_watchedFolders)
dirs << dir.canonicalPath();
}
#endif
dirs << QFileSystemWatcher::directories();
return dirs;
}
void FileSystemWatcher::addPath(const QString &path)
{
if (path.isEmpty()) return;
#if !defined Q_OS_HAIKU
const QDir dir(path);
#if !defined Q_OS_WIN && !defined Q_OS_HAIKU
QDir dir(path);
if (!dir.exists()) return;
// Check if the path points to a network file system or not
if (Utils::Fs::isNetworkFileSystem(path)) {
if (isNetworkFileSystem(path)) {
// Network mode
LogMsg(tr("Watching remote folder: \"%1\"").arg(Utils::Fs::toNativePath(path)));
qDebug("Network folder detected: %s", qUtf8Printable(path));
qDebug("Using file polling mode instead of inotify...");
m_watchedFolders << dir;
m_watchTimer.start(WATCH_INTERVAL);
return;
// Set up the watch timer
if (!m_watchTimer) {
m_watchTimer = new QTimer(this);
connect(m_watchTimer, SIGNAL(timeout()), SLOT(scanNetworkFolders()));
m_watchTimer->start(WATCH_INTERVAL); // 5 sec
}
}
else {
#endif
// Normal mode
qDebug("FS Watching is watching %s in normal mode", qUtf8Printable(path));
QFileSystemWatcher::addPath(path);
scanLocalFolder(path);
#if !defined Q_OS_WIN && !defined Q_OS_HAIKU
}
#endif
// Normal mode
LogMsg(tr("Watching local folder: \"%1\"").arg(Utils::Fs::toNativePath(path)));
QFileSystemWatcher::addPath(path);
scanLocalFolder(path);
}
void FileSystemWatcher::removePath(const QString &path)
{
if (m_watchedFolders.removeOne(path)) {
if (m_watchedFolders.isEmpty())
m_watchTimer.stop();
return;
#ifndef Q_OS_WIN
QDir dir(path);
for (int i = 0; i < m_watchedFolders.count(); ++i) {
if (QDir(m_watchedFolders.at(i)) == dir) {
m_watchedFolders.removeAt(i);
if (m_watchedFolders.isEmpty())
delete m_watchTimer;
return;
}
}
#endif
// Normal mode
QFileSystemWatcher::removePath(path);
}
void FileSystemWatcher::scanLocalFolder(const QString &path)
void FileSystemWatcher::scanLocalFolder(QString path)
{
QTimer::singleShot(2000, this, [this, path]() { processTorrentsInDir(path); });
qDebug("scanLocalFolder(%s) called", qUtf8Printable(path));
QStringList torrents;
// Local folders scan
addTorrentsFromDir(QDir(path), torrents);
// Report detected torrent files
if (!torrents.empty()) {
qDebug("The following files are being reported: %s", qUtf8Printable(torrents.join("\n")));
emit torrentsAdded(torrents);
}
}
void FileSystemWatcher::scanNetworkFolders()
{
for (const QDir &dir : asConst(m_watchedFolders))
processTorrentsInDir(dir);
#ifndef Q_OS_WIN
qDebug("scanNetworkFolders() called");
QStringList torrents;
// Network folders scan
foreach (const QDir &dir, m_watchedFolders) {
//qDebug("FSWatcher: Polling manually folder %s", qUtf8Printable(dir.path()));
addTorrentsFromDir(dir, torrents);
}
// Report detected torrent files
if (!torrents.empty()) {
qDebug("The following files are being reported: %s", qUtf8Printable(torrents.join("\n")));
emit torrentsAdded(torrents);
}
#endif
}
void FileSystemWatcher::processPartialTorrents()
@@ -122,33 +145,32 @@ void FileSystemWatcher::processPartialTorrents()
QStringList noLongerPartial;
// Check which torrents are still partial
Dict::removeIf(m_partialTorrents, [&noLongerPartial](const QString &torrentPath, int &value)
{
if (!QFile::exists(torrentPath))
return true;
if (BitTorrent::TorrentInfo::loadFromFile(torrentPath).isValid()) {
foreach (const QString &torrentPath, m_partialTorrents.keys()) {
if (!QFile::exists(torrentPath)) {
m_partialTorrents.remove(torrentPath);
}
else if (BitTorrent::TorrentInfo::loadFromFile(torrentPath).isValid()) {
noLongerPartial << torrentPath;
return true;
m_partialTorrents.remove(torrentPath);
}
if (value >= MAX_PARTIAL_RETRIES) {
QFile::rename(torrentPath, torrentPath + ".qbt_rejected");
return true;
else if (m_partialTorrents[torrentPath] >= MAX_PARTIAL_RETRIES) {
m_partialTorrents.remove(torrentPath);
QFile::rename(torrentPath, torrentPath + ".invalid");
}
++value;
return false;
});
else {
++m_partialTorrents[torrentPath];
}
}
// Stop the partial timer if necessary
if (m_partialTorrents.empty()) {
m_partialTorrentTimer.stop();
m_partialTorrentTimer->stop();
m_partialTorrentTimer->deleteLater();
qDebug("No longer any partial torrent.");
}
else {
qDebug("Still %d partial torrents after delayed processing.", m_partialTorrents.count());
m_partialTorrentTimer.start(WATCH_INTERVAL);
m_partialTorrentTimer->start(WATCH_INTERVAL);
}
// Notify of new torrents
@@ -156,23 +178,99 @@ void FileSystemWatcher::processPartialTorrents()
emit torrentsAdded(noLongerPartial);
}
void FileSystemWatcher::processTorrentsInDir(const QDir &dir)
void FileSystemWatcher::startPartialTorrentTimer()
{
QStringList torrents;
const QStringList files = dir.entryList({"*.torrent", "*.magnet"}, QDir::Files);
for (const QString &file : files) {
Q_ASSERT(!m_partialTorrents.isEmpty());
if (!m_partialTorrentTimer) {
m_partialTorrentTimer = new QTimer();
connect(m_partialTorrentTimer, SIGNAL(timeout()), SLOT(processPartialTorrents()));
m_partialTorrentTimer->setSingleShot(true);
m_partialTorrentTimer->start(WATCH_INTERVAL);
}
}
void FileSystemWatcher::addTorrentsFromDir(const QDir &dir, QStringList &torrents)
{
const QStringList files = dir.entryList(m_filters, QDir::Files, QDir::Unsorted);
foreach (const QString &file, files) {
const QString fileAbsPath = dir.absoluteFilePath(file);
if (file.endsWith(".magnet", Qt::CaseInsensitive))
if (fileAbsPath.endsWith(".magnet")) {
torrents << fileAbsPath;
else if (BitTorrent::TorrentInfo::loadFromFile(fileAbsPath).isValid())
}
else if (BitTorrent::TorrentInfo::loadFromFile(fileAbsPath).isValid()) {
torrents << fileAbsPath;
else if (!m_partialTorrents.contains(fileAbsPath))
m_partialTorrents[fileAbsPath] = 0;
}
else if (!m_partialTorrents.contains(fileAbsPath)) {
qDebug("Partial torrent detected at: %s", qUtf8Printable(fileAbsPath));
qDebug("Delay the file's processing...");
m_partialTorrents.insert(fileAbsPath, 0);
}
}
if (!torrents.empty())
emit torrentsAdded(torrents);
if (!m_partialTorrents.empty() && !m_partialTorrentTimer.isActive())
m_partialTorrentTimer.start(WATCH_INTERVAL);
if (!m_partialTorrents.empty())
startPartialTorrentTimer();
}
#if !defined Q_OS_WIN && !defined Q_OS_HAIKU
bool FileSystemWatcher::isNetworkFileSystem(QString path)
{
QString file = path;
if (!file.endsWith("/"))
file += "/";
file += ".";
struct statfs buf;
if (!statfs(file.toLocal8Bit().constData(), &buf)) {
#ifdef Q_OS_MAC
// XXX: should we make sure HAVE_STRUCT_FSSTAT_F_FSTYPENAME is defined?
return ((strcmp(buf.f_fstypename, "nfs") == 0) || (strcmp(buf.f_fstypename, "cifs") == 0) || (strcmp(buf.f_fstypename, "smbfs") == 0));
#else
return ((buf.f_type == static_cast<long>(CIFS_MAGIC_NUMBER))
|| (buf.f_type == static_cast<long>(NFS_SUPER_MAGIC))
|| (buf.f_type == static_cast<long>(SMB_SUPER_MAGIC)));
#endif
}
else {
std::cerr << "Error: statfs() call failed for " << qPrintable(file) << ". Supposing it is a local folder..." << std::endl;
switch(errno) {
case EACCES:
std::cerr << "Search permission is denied for a component of the path prefix of the path" << std::endl;
break;
case EFAULT:
std::cerr << "Buf or path points to an invalid address" << std::endl;
break;
case EINTR:
std::cerr << "This call was interrupted by a signal" << std::endl;
break;
case EIO:
std::cerr << "I/O Error" << std::endl;
break;
case ELOOP:
std::cerr << "Too many symlinks" << std::endl;
break;
case ENAMETOOLONG:
std::cerr << "path is too long" << std::endl;
break;
case ENOENT:
std::cerr << "The file referred by path does not exist" << std::endl;
break;
case ENOMEM:
std::cerr << "Insufficient kernel memory" << std::endl;
break;
case ENOSYS:
std::cerr << "The file system does not detect this call" << std::endl;
break;
case ENOTDIR:
std::cerr << "A component of the path is not a directory" << std::endl;
break;
case EOVERFLOW:
std::cerr << "Some values were too large to be represented in the struct" << std::endl;
break;
default:
std::cerr << "Unknown error" << std::endl;
}
std::cerr << "Errno: " << errno << std::endl;
return false;
}
}
#endif

View File

@@ -1,37 +1,10 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018
*
* 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 FILESYSTEMWATCHER_H
#define FILESYSTEMWATCHER_H
#include <QDir>
#include <QFileSystemWatcher>
#include <QHash>
#include <QPointer>
#include <QStringList>
#include <QTimer>
@@ -45,6 +18,7 @@ class FileSystemWatcher : public QFileSystemWatcher
public:
explicit FileSystemWatcher(QObject *parent = nullptr);
~FileSystemWatcher();
QStringList directories() const;
void addPath(const QString &path);
@@ -54,19 +28,25 @@ signals:
void torrentsAdded(const QStringList &pathList);
protected slots:
void scanLocalFolder(const QString &path);
void processPartialTorrents();
void scanLocalFolder(QString path);
void scanNetworkFolders();
void processPartialTorrents();
private:
void processTorrentsInDir(const QDir &dir);
void startPartialTorrentTimer();
void addTorrentsFromDir(const QDir &dir, QStringList &torrents);
#if !defined Q_OS_WIN && !defined Q_OS_HAIKU
static bool isNetworkFileSystem(QString path);
#endif
#ifndef Q_OS_WIN
QList<QDir> m_watchedFolders;
QPointer<QTimer> m_watchTimer;
#endif
QStringList m_filters;
// Partial torrents
QHash<QString, int> m_partialTorrents;
QTimer m_partialTorrentTimer;
QList<QDir> m_watchedFolders;
QTimer m_watchTimer;
QPointer<QTimer> m_partialTorrentTimer;
};
#endif // FILESYSTEMWATCHER_H

View File

@@ -26,21 +26,5 @@
* exception statement from your version.
*/
#pragma once
#include <type_traits>
#include <QtGlobal>
const char C_TORRENT_FILE_EXTENSION[] = ".torrent";
const int MAX_TORRENT_SIZE = 100 * 1024 * 1024; // 100 MiB
template <typename T>
constexpr typename std::add_const<T>::type &asConst(T &t) noexcept { return t; }
// Forward rvalue as const
template <typename T>
constexpr typename std::add_const<T>::type asConst(T &&t) noexcept { return std::move(t); }
// Prevent const rvalue arguments
template <typename T>
void asConst(const T &&) = delete;

View File

@@ -1,8 +1,7 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018 Mike Tzou (Chocobo1)
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Ishan Arora and Christophe Dumez <chris@qbittorrent.org>
* Copyright (C) 2006 Ishan Arora and Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -26,13 +25,15 @@
* 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.
*
* Contact : chris@qbittorrent.org
*/
#include "connection.h"
#include <QRegExp>
#include <QTcpSocket>
#include "base/logger.h"
#include "irequesthandler.h"
#include "requestparser.h"
#include "responsegenerator.h"
@@ -46,7 +47,7 @@ Connection::Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObj
{
m_socket->setParent(this);
m_idleTimer.start();
connect(m_socket, &QTcpSocket::readyRead, this, &Connection::read);
connect(m_socket, SIGNAL(readyRead()), SLOT(read()));
}
Connection::~Connection()
@@ -57,64 +58,37 @@ Connection::~Connection()
void Connection::read()
{
m_idleTimer.restart();
m_receivedData.append(m_socket->readAll());
Request request;
RequestParser::ErrorCode err = RequestParser::parse(m_receivedData, request); // TODO: transform request headers to lowercase
while (!m_receivedData.isEmpty()) {
const RequestParser::ParseResult result = RequestParser::parse(m_receivedData);
switch (err) {
case RequestParser::IncompleteRequest:
// Partial request waiting for the rest
break;
switch (result.status) {
case RequestParser::ParseStatus::Incomplete: {
const long bufferLimit = RequestParser::MAX_CONTENT_SIZE * 1.1; // some margin for headers
if (m_receivedData.size() > bufferLimit) {
Logger::instance()->addMessage(tr("Http request size exceeds limiation, closing socket. Limit: %1, IP: %2")
.arg(bufferLimit).arg(m_socket->peerAddress().toString()), Log::WARNING);
case RequestParser::BadRequest:
sendResponse(Response(400, "Bad Request"));
m_receivedData.clear();
break;
Response resp(413, "Payload Too Large");
resp.headers[HEADER_CONNECTION] = "close";
case RequestParser::NoError:
const Environment env {m_socket->localAddress(), m_socket->localPort(), m_socket->peerAddress(), m_socket->peerPort()};
sendResponse(resp);
m_socket->close();
}
}
return;
case RequestParser::ParseStatus::BadRequest: {
Logger::instance()->addMessage(tr("Bad Http request, closing socket. IP: %1")
.arg(m_socket->peerAddress().toString()), Log::WARNING);
Response resp(400, "Bad Request");
resp.headers[HEADER_CONNECTION] = "close";
sendResponse(resp);
m_socket->close();
}
return;
case RequestParser::ParseStatus::OK: {
const Environment env {m_socket->localAddress(), m_socket->localPort(), m_socket->peerAddress(), m_socket->peerPort()};
Response resp = m_requestHandler->processRequest(result.request, env);
if (acceptsGzipEncoding(result.request.headers["accept-encoding"]))
resp.headers[HEADER_CONTENT_ENCODING] = "gzip";
resp.headers[HEADER_CONNECTION] = "keep-alive";
sendResponse(resp);
m_receivedData = m_receivedData.mid(result.frameSize);
}
break;
default:
Q_ASSERT(false);
return;
}
Response response = m_requestHandler->processRequest(request, env);
if (acceptsGzipEncoding(request.headers["accept-encoding"]))
response.headers[HEADER_CONTENT_ENCODING] = "gzip";
sendResponse(response);
m_receivedData.clear();
break;
}
}
void Connection::sendResponse(const Response &response) const
void Connection::sendResponse(const Response &response)
{
m_socket->write(toByteArray(response));
m_socket->close(); // TODO: remove when HTTP pipelining is supported
}
bool Connection::hasExpired(const qint64 timeout) const
@@ -133,7 +107,7 @@ bool Connection::acceptsGzipEncoding(QString codings)
const auto isCodingAvailable = [](const QStringList &list, const QString &encoding) -> bool
{
for (const QString &str : list) {
foreach (const QString &str, list) {
if (!str.startsWith(encoding))
continue;

View File

@@ -1,7 +1,7 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Ishan Arora and Christophe Dumez <chris@qbittorrent.org>
* Copyright (C) 2006 Ishan Arora and Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -25,6 +25,8 @@
* 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.
*
* Contact : chris@qbittorrent.org
*/
@@ -48,7 +50,7 @@ namespace Http
Q_DISABLE_COPY(Connection)
public:
Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = nullptr);
Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = 0);
~Connection();
bool hasExpired(qint64 timeout) const;
@@ -59,7 +61,7 @@ namespace Http
private:
static bool acceptsGzipEncoding(QString codings);
void sendResponse(const Response &response) const;
void sendResponse(const Response &response);
QTcpSocket *m_socket;
IRequestHandler *m_requestHandler;

View File

@@ -1,81 +0,0 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2017 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 "httperror.h"
HTTPError::HTTPError(int statusCode, const QString &statusText, const QString &message)
: RuntimeError {message}
, m_statusCode {statusCode}
, m_statusText {statusText}
{
}
int HTTPError::statusCode() const
{
return m_statusCode;
}
QString HTTPError::statusText() const
{
return m_statusText;
}
BadRequestHTTPError::BadRequestHTTPError(const QString &message)
: HTTPError(400, QLatin1String("Bad Request"), message)
{
}
ConflictHTTPError::ConflictHTTPError(const QString &message)
: HTTPError(409, QLatin1String("Conflict"), message)
{
}
ForbiddenHTTPError::ForbiddenHTTPError(const QString &message)
: HTTPError(403, QLatin1String("Forbidden"), message)
{
}
NotFoundHTTPError::NotFoundHTTPError(const QString &message)
: HTTPError(404, QLatin1String("Not Found"), message)
{
}
UnsupportedMediaTypeHTTPError::UnsupportedMediaTypeHTTPError(const QString &message)
: HTTPError(415, QLatin1String("Unsupported Media Type"), message)
{
}
UnauthorizedHTTPError::UnauthorizedHTTPError(const QString &message)
: HTTPError(401, QLatin1String("Unauthorized"), message)
{
}
InternalServerErrorHTTPError::InternalServerErrorHTTPError(const QString &message)
: HTTPError(500, QLatin1String("Internal Server Error"), message)
{
}

View File

@@ -1,86 +0,0 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2017 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.
*/
#pragma once
#include "base/exceptions.h"
class HTTPError : public RuntimeError
{
public:
HTTPError(int statusCode, const QString &statusText, const QString &message = "");
int statusCode() const;
QString statusText() const;
private:
const int m_statusCode;
const QString m_statusText;
};
class BadRequestHTTPError : public HTTPError
{
public:
explicit BadRequestHTTPError(const QString &message = "");
};
class ForbiddenHTTPError : public HTTPError
{
public:
explicit ForbiddenHTTPError(const QString &message = "");
};
class NotFoundHTTPError : public HTTPError
{
public:
explicit NotFoundHTTPError(const QString &message = "");
};
class ConflictHTTPError : public HTTPError
{
public:
explicit ConflictHTTPError(const QString &message = "");
};
class UnsupportedMediaTypeHTTPError : public HTTPError
{
public:
explicit UnsupportedMediaTypeHTTPError(const QString &message = "");
};
class UnauthorizedHTTPError : public HTTPError
{
public:
explicit UnauthorizedHTTPError(const QString &message = "");
};
class InternalServerErrorHTTPError : public HTTPError
{
public:
explicit InternalServerErrorHTTPError(const QString &message = "");
};

View File

@@ -1,6 +1,5 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018 Mike Tzou (Chocobo1)
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Ishan Arora and Christophe Dumez <chris@qbittorrent.org>
*
@@ -31,237 +30,242 @@
#include "requestparser.h"
#include <QDebug>
#include <QRegularExpression>
#include <QDir>
#include <QStringList>
#include <QUrl>
#include <QUrlQuery>
#include "base/global.h"
#include "base/utils/bytearray.h"
#include "base/utils/string.h"
const QByteArray EOL("\r\n");
const QByteArray EOH("\r\n\r\n");
inline QString unquoted(const QString &str)
{
if ((str[0] == '\"') && (str[str.length() - 1] == '\"'))
return str.mid(1, str.length() - 2);
return str;
}
using namespace Http;
using namespace Utils::ByteArray;
using QStringPair = QPair<QString, QString>;
namespace
RequestParser::ErrorCode RequestParser::parse(const QByteArray &data, Request &request, uint maxContentLength)
{
const QByteArray EOH = QByteArray(CRLF).repeated(2);
const QByteArray viewWithoutEndingWith(const QByteArray &in, const QByteArray &str)
{
if (in.endsWith(str))
return QByteArray::fromRawData(in.constData(), (in.size() - str.size()));
return in;
}
bool parseHeaderLine(const QString &line, QStringMap &out)
{
// [rfc7230] 3.2. Header Fields
const int i = line.indexOf(':');
if (i <= 0) {
qWarning() << Q_FUNC_INFO << "invalid http header:" << line;
return false;
}
const QString name = line.leftRef(i).trimmed().toString().toLower();
const QString value = line.midRef(i + 1).trimmed().toString();
out[name] = value;
return true;
}
return RequestParser(maxContentLength).parseHttpRequest(data, request);
}
RequestParser::RequestParser()
RequestParser::RequestParser(uint maxContentLength)
: m_maxContentLength(maxContentLength)
{
}
RequestParser::ParseResult RequestParser::parse(const QByteArray &data)
RequestParser::ErrorCode RequestParser::parseHttpRequest(const QByteArray &data, Request &request)
{
// Warning! Header names are converted to lowercase
return RequestParser().doParse(data);
}
m_request = Request();
RequestParser::ParseResult RequestParser::doParse(const QByteArray &data)
{
// we don't handle malformed requests which use double `LF` as delimiter
// Parse HTTP request header
const int headerEnd = data.indexOf(EOH);
if (headerEnd < 0) {
qDebug() << Q_FUNC_INFO << "incomplete request";
return {ParseStatus::Incomplete, Request(), 0};
return IncompleteRequest;
}
const QString httpHeaders = QString::fromLatin1(data.constData(), headerEnd);
if (!parseStartLines(httpHeaders)) {
if (!parseHttpHeader(data.left(headerEnd))) {
qWarning() << Q_FUNC_INFO << "header parsing error";
return {ParseStatus::BadRequest, Request(), 0};
return BadRequest;
}
const int headerLength = headerEnd + EOH.length();
// handle supported methods
if ((m_request.method == HEADER_REQUEST_METHOD_GET) || (m_request.method == HEADER_REQUEST_METHOD_HEAD))
return {ParseStatus::OK, m_request, headerLength};
if (m_request.method == HEADER_REQUEST_METHOD_POST) {
bool ok = false;
const int contentLength = m_request.headers[HEADER_CONTENT_LENGTH].toInt(&ok);
if (!ok || (contentLength < 0)) {
qWarning() << Q_FUNC_INFO << "bad request: content-length invalid";
return {ParseStatus::BadRequest, Request(), 0};
// Parse HTTP request message
if (m_request.headers.contains("content-length")) {
int contentLength = m_request.headers["content-length"].toInt();
if (contentLength < 0) {
qWarning() << Q_FUNC_INFO << "bad request: content-length is negative";
return BadRequest;
}
if (contentLength > MAX_CONTENT_SIZE) {
if (contentLength > static_cast<int>(m_maxContentLength)) {
qWarning() << Q_FUNC_INFO << "bad request: message too long";
return {ParseStatus::BadRequest, Request(), 0};
return BadRequest;
}
if (contentLength > 0) {
const QByteArray httpBodyView = midView(data, headerLength, contentLength);
if (httpBodyView.length() < contentLength) {
qDebug() << Q_FUNC_INFO << "incomplete request";
return {ParseStatus::Incomplete, Request(), 0};
}
if (!parsePostMessage(httpBodyView)) {
qWarning() << Q_FUNC_INFO << "message body parsing error";
return {ParseStatus::BadRequest, Request(), 0};
}
QByteArray content = data.mid(headerEnd + EOH.length(), contentLength);
if (content.length() < contentLength) {
qDebug() << Q_FUNC_INFO << "incomplete request";
return IncompleteRequest;
}
return {ParseStatus::OK, m_request, (headerLength + contentLength)};
if ((contentLength > 0) && !parseContent(content)) {
qWarning() << Q_FUNC_INFO << "message parsing error";
return BadRequest;
}
}
qWarning() << Q_FUNC_INFO << "unsupported request method: " << m_request.method;
return {ParseStatus::BadRequest, Request(), 0}; // TODO: SHOULD respond "501 Not Implemented"
// qDebug() << Q_FUNC_INFO;
// qDebug() << "HTTP Request header:";
// qDebug() << data.left(headerEnd) << "\n";
request = m_request;
return NoError;
}
bool RequestParser::parseStartLines(const QString &data)
bool RequestParser::parseStartingLine(const QString &line)
{
// we don't handle malformed request which uses `LF` for newline
const QVector<QStringRef> lines = data.splitRef(CRLF, QString::SkipEmptyParts);
const QRegExp rx("^([A-Z]+)\\s+(\\S+)\\s+HTTP/\\d\\.\\d$");
// [rfc7230] 3.2.2. Field Order
QStringList requestLines;
for (const auto &line : lines) {
if (line.at(0).isSpace() && !requestLines.isEmpty()) {
// continuation of previous line
requestLines.last() += line.toString();
}
else {
requestLines += line.toString();
if (rx.indexIn(line.trimmed()) >= 0) {
m_request.method = rx.cap(1);
QUrl url = QUrl::fromEncoded(rx.cap(2).toLatin1());
m_request.path = url.path(); // Path
// Parse GET parameters
QListIterator<QPair<QString, QString> > i(QUrlQuery(url).queryItems());
while (i.hasNext()) {
QPair<QString, QString> pair = i.next();
m_request.gets[pair.first] = pair.second;
}
return true;
}
if (requestLines.isEmpty())
return false;
if (!parseRequestLine(requestLines[0]))
return false;
for (auto i = ++(requestLines.begin()); i != requestLines.end(); ++i) {
if (!parseHeaderLine(*i, m_request.headers))
return false;
}
return true;
qWarning() << Q_FUNC_INFO << "invalid http header:" << line;
return false;
}
bool RequestParser::parseRequestLine(const QString &line)
bool RequestParser::parseHeaderLine(const QString &line, QPair<QString, QString> &out)
{
// [rfc7230] 3.1.1. Request Line
const QRegularExpression re(QLatin1String("^([A-Z]+)\\s+(\\S+)\\s+HTTP\\/(\\d\\.\\d)$"));
const QRegularExpressionMatch match = re.match(line);
if (!match.hasMatch()) {
int i = line.indexOf(QLatin1Char(':'));
if (i == -1) {
qWarning() << Q_FUNC_INFO << "invalid http header:" << line;
return false;
}
// Request Methods
m_request.method = match.captured(1);
out = qMakePair(line.left(i).trimmed().toLower(), line.mid(i + 1).trimmed());
return true;
}
// Request Target
const QByteArray url {match.captured(2).toLatin1()};
const int sepPos = url.indexOf('?');
const QByteArray pathComponent = ((sepPos == -1) ? url : midView(url, 0, sepPos));
bool RequestParser::parseHttpHeader(const QByteArray &data)
{
QString str = QString::fromUtf8(data);
QStringList lines = str.trimmed().split(EOL);
m_request.path = QString::fromUtf8(QByteArray::fromPercentEncoding(pathComponent));
if (sepPos >= 0) {
const QByteArray query = midView(url, (sepPos + 1));
// [rfc3986] 2.4 When to Encode or Decode
// URL components should be separated before percent-decoding
for (const QByteArray &param : asConst(splitToViews(query, "&"))) {
const int eqCharPos = param.indexOf('=');
if (eqCharPos <= 0) continue; // ignores params without name
const QByteArray nameComponent = midView(param, 0, eqCharPos);
const QByteArray valueComponent = midView(param, (eqCharPos + 1));
const QString paramName = QString::fromUtf8(QByteArray::fromPercentEncoding(nameComponent).replace('+', ' '));
const QByteArray paramValue = QByteArray::fromPercentEncoding(valueComponent).replace('+', ' ');
m_request.query[paramName] = paramValue;
QStringList headerLines;
foreach (const QString &line, lines) {
if (line[0].isSpace()) { // header line continuation
if (!headerLines.isEmpty()) { // really continuation
headerLines.last() += QLatin1Char(' ');
headerLines.last() += line.trimmed();
}
}
else {
headerLines.append(line);
}
}
// HTTP-version
m_request.version = match.captured(3);
if (headerLines.isEmpty())
return false; // Empty header
QStringList::Iterator it = headerLines.begin();
if (!parseStartingLine(*it))
return false;
++it;
for (; it != headerLines.end(); ++it) {
QPair<QString, QString> header;
if (!parseHeaderLine(*it, header))
return false;
m_request.headers[header.first] = header.second;
}
return true;
}
bool RequestParser::parsePostMessage(const QByteArray &data)
QList<QByteArray> RequestParser::splitMultipartData(const QByteArray &data, const QByteArray &boundary)
{
// parse POST message-body
const QString contentType = m_request.headers[HEADER_CONTENT_TYPE];
const QString contentTypeLower = contentType.toLower();
QList<QByteArray> ret;
QByteArray sep = boundary + EOL;
const int sepLength = sep.size();
// application/x-www-form-urlencoded
if (contentTypeLower.startsWith(CONTENT_TYPE_FORM_ENCODED)) {
// [URL Standard] 5.1 application/x-www-form-urlencoded parsing
const QByteArray processedData = QByteArray(data).replace('+', ' ');
int start = 0, end = 0;
if ((end = data.indexOf(sep, start)) >= 0) {
start = end + sepLength; // skip first boundary
QListIterator<QStringPair> i(QUrlQuery(processedData).queryItems(QUrl::FullyDecoded));
while ((end = data.indexOf(sep, start)) >= 0) {
ret << data.mid(start, end - EOL.length() - start);
start = end + sepLength;
}
// last or single part
sep = boundary + "--" + EOL;
if ((end = data.indexOf(sep, start)) >= 0)
ret << data.mid(start, end - EOL.length() - start);
}
return ret;
}
bool RequestParser::parseContent(const QByteArray &data)
{
// Parse message content
qDebug() << Q_FUNC_INFO << "Content-Length: " << m_request.headers["content-length"];
qDebug() << Q_FUNC_INFO << "data.size(): " << data.size();
// Parse url-encoded POST data
if (m_request.headers["content-type"].startsWith("application/x-www-form-urlencoded")) {
QUrl url;
url.setQuery(data);
QListIterator<QPair<QString, QString> > i(QUrlQuery(url).queryItems(QUrl::FullyDecoded));
while (i.hasNext()) {
const QStringPair pair = i.next();
m_request.posts[pair.first] = pair.second;
QPair<QString, QString> pair = i.next();
m_request.posts[pair.first.toLower()] = pair.second;
}
return true;
}
// multipart/form-data
if (contentTypeLower.startsWith(CONTENT_TYPE_FORM_DATA)) {
// [rfc2046] 5.1.1. Common Syntax
// Parse multipart/form data (torrent file)
/**
data has the following format (if boundary is "cH2ae0GI3KM7GI3Ij5ae0ei4Ij5Ij5")
// find boundary delimiter
const QLatin1String boundaryFieldName("boundary=");
const int idx = contentType.indexOf(boundaryFieldName);
if (idx < 0) {
qWarning() << Q_FUNC_INFO << "Could not find boundary in multipart/form-data header!";
return false;
--cH2ae0GI3KM7GI3Ij5ae0ei4Ij5Ij5
Content-Disposition: form-data; name=\"Filename\"
PB020344.torrent
--cH2ae0GI3KM7GI3Ij5ae0ei4Ij5Ij5
Content-Disposition: form-data; name=\"torrentfile"; filename=\"PB020344.torrent\"
Content-Type: application/x-bittorrent
BINARY DATA IS HERE
--cH2ae0GI3KM7GI3Ij5ae0ei4Ij5Ij5
Content-Disposition: form-data; name=\"Upload\"
Submit Query
--cH2ae0GI3KM7GI3Ij5ae0ei4Ij5Ij5--
**/
QString contentType = m_request.headers["content-type"];
if (contentType.startsWith("multipart/form-data")) {
const QRegExp boundaryRegexQuoted("boundary=\"([ \\w'()+,-\\./:=\\?]+)\"");
const QRegExp boundaryRegexNotQuoted("boundary=([\\w'()+,-\\./:=\\?]+)");
QByteArray boundary;
if (boundaryRegexQuoted.indexIn(contentType) < 0) {
if (boundaryRegexNotQuoted.indexIn(contentType) < 0) {
qWarning() << "Could not find boundary in multipart/form-data header!";
return false;
}
else {
boundary = "--" + boundaryRegexNotQuoted.cap(1).toLatin1();
}
}
else {
boundary = "--" + boundaryRegexQuoted.cap(1).toLatin1();
}
const QByteArray delimiter = Utils::String::unquote(contentType.midRef(idx + boundaryFieldName.size())).toLatin1();
if (delimiter.isEmpty()) {
qWarning() << Q_FUNC_INFO << "boundary delimiter field empty!";
return false;
}
qDebug() << "Boundary is " << boundary;
QList<QByteArray> parts = splitMultipartData(data, boundary);
qDebug() << parts.size() << "parts in data";
// split data by "dash-boundary"
const QByteArray dashDelimiter = QByteArray("--") + delimiter + CRLF;
QList<QByteArray> multipart = splitToViews(data, dashDelimiter, QString::SkipEmptyParts);
if (multipart.isEmpty()) {
qWarning() << Q_FUNC_INFO << "multipart empty";
return false;
}
// remove the ending delimiter
const QByteArray endDelimiter = QByteArray("--") + delimiter + QByteArray("--") + CRLF;
multipart.push_back(viewWithoutEndingWith(multipart.takeLast(), endDelimiter));
for (const auto &part : multipart) {
foreach (const QByteArray& part, parts) {
if (!parseFormData(part))
return false;
}
@@ -269,60 +273,71 @@ bool RequestParser::parsePostMessage(const QByteArray &data)
return true;
}
qWarning() << Q_FUNC_INFO << "unknown content type:" << contentType;
qWarning() << Q_FUNC_INFO << "unknown content type:" << qPrintable(contentType);
return false;
}
bool RequestParser::parseFormData(const QByteArray &data)
{
const QList<QByteArray> list = splitToViews(data, EOH, QString::KeepEmptyParts);
if (list.size() != 2) {
qWarning() << Q_FUNC_INFO << "multipart/form-data format error";
// Parse form data header
const int headerEnd = data.indexOf(EOH);
if (headerEnd < 0) {
qDebug() << "Invalid form data: \n" << data;
return false;
}
const QString headers = QString::fromLatin1(list[0]);
const QByteArray payload = viewWithoutEndingWith(list[1], CRLF);
QString headerStr = QString::fromUtf8(data.left(headerEnd));
QStringList lines = headerStr.trimmed().split(EOL);
QStringMap headers;
foreach (const QString& line, lines) {
QPair<QString, QString> header;
if (!parseHeaderLine(line, header))
return false;
QStringMap headersMap;
const QVector<QStringRef> headerLines = headers.splitRef(CRLF, QString::SkipEmptyParts);
for (const auto &line : headerLines) {
if (line.trimmed().startsWith(HEADER_CONTENT_DISPOSITION, Qt::CaseInsensitive)) {
// extract out filename & name
const QVector<QStringRef> directives = line.split(';', QString::SkipEmptyParts);
for (const auto &directive : directives) {
const int idx = directive.indexOf('=');
if (idx < 0)
continue;
const QString name = directive.left(idx).trimmed().toString().toLower();
const QString value = Utils::String::unquote(directive.mid(idx + 1).trimmed()).toString();
headersMap[name] = value;
}
}
else {
if (!parseHeaderLine(line.toString(), headersMap))
return false;
}
headers[header.first] = header.second;
}
// pick data
const QLatin1String filename("filename");
const QLatin1String name("name");
if (headersMap.contains(filename)) {
m_request.files.append({headersMap[filename], headersMap[HEADER_CONTENT_TYPE], payload});
QStringMap disposition;
if (!headers.contains("content-disposition")
|| !parseHeaderValue(headers["content-disposition"], disposition)
|| !disposition.contains("name")) {
qDebug() << "Invalid form data header: \n" << headerStr;
return false;
}
else if (headersMap.contains(name)) {
m_request.posts[headersMap[name]] = payload;
if (disposition.contains("filename")) {
UploadedFile ufile;
ufile.filename = disposition["filename"];
ufile.type = disposition["content-type"];
ufile.data = data.mid(headerEnd + EOH.length());
m_request.files.append(ufile);
}
else {
// malformed
qWarning() << Q_FUNC_INFO << "multipart/form-data header error";
return false;
m_request.posts[disposition["name"]] = QString::fromUtf8(data.mid(headerEnd + EOH.length()));
}
return true;
}
bool RequestParser::parseHeaderValue(const QString &value, QStringMap &out)
{
int pos = value.indexOf(QLatin1Char(';'));
if (pos == -1) {
out[""] = value.trimmed();
return true;
}
out[""] = value.left(pos).trimmed();
QRegExp rx(";\\s*([^=;\"]+)\\s*=\\s*(\"[^\"]*\"|[^\";\\s]+)\\s*");
while (rx.indexIn(value, pos) == pos) {
out[rx.cap(1).trimmed()] = unquoted(rx.cap(2));
pos += rx.cap(0).length();
}
if (pos != value.length())
return false;
return true;
}

View File

@@ -1,6 +1,5 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018 Mike Tzou (Chocobo1)
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Ishan Arora and Christophe Dumez <chris@qbittorrent.org>
*
@@ -38,35 +37,32 @@ namespace Http
class RequestParser
{
public:
enum class ParseStatus
enum ErrorCode
{
OK,
Incomplete,
NoError = 0,
IncompleteRequest,
BadRequest
};
struct ParseResult
{
// when `status != ParseStatus::OK`, `request` & `frameSize` are undefined
ParseStatus status;
Request request;
long frameSize; // http request frame size (bytes)
};
static ParseResult parse(const QByteArray &data);
static const long MAX_CONTENT_SIZE = 64 * 1024 * 1024; // 64 MB
// when result != NoError parsed request is undefined
// Warning! Header names are converted to lower-case.
static ErrorCode parse(const QByteArray &data, Request &request, uint maxContentLength = 10000000 /* ~10MB */);
private:
RequestParser();
RequestParser(uint maxContentLength);
ParseResult doParse(const QByteArray &data);
bool parseStartLines(const QString &data);
bool parseRequestLine(const QString &line);
ErrorCode parseHttpRequest(const QByteArray &data, Request &request);
bool parsePostMessage(const QByteArray &data);
bool parseHttpHeader(const QByteArray &data);
bool parseStartingLine(const QString &line);
bool parseContent(const QByteArray &data);
bool parseFormData(const QByteArray &data);
QList<QByteArray> splitMultipartData(const QByteArray &data, const QByteArray &boundary);
static bool parseHeaderLine(const QString &line, QPair<QString, QString> &out);
static bool parseHeaderValue(const QString &value, QStringMap &out);
const uint m_maxContentLength;
Request m_request;
};
}

View File

@@ -30,6 +30,11 @@
using namespace Http;
ResponseBuilder::ResponseBuilder(QObject *parent)
: QObject(parent)
{
}
void ResponseBuilder::status(uint code, const QString &text)
{
m_response.status = ResponseStatus(code, text);

View File

@@ -29,13 +29,17 @@
#ifndef HTTP_RESPONSEBUILDER_H
#define HTTP_RESPONSEBUILDER_H
#include <QObject>
#include "types.h"
namespace Http
{
class ResponseBuilder
class ResponseBuilder : public QObject
{
public:
explicit ResponseBuilder(QObject *parent = nullptr);
protected:
void status(uint code = 200, const QString &text = QLatin1String("OK"));
void header(const QString &name, const QString &value);
void print(const QString &text, const QString &type = CONTENT_TYPE_HTML);

View File

@@ -97,23 +97,16 @@ void Server::incomingConnection(qintptr socketDescriptor)
#endif
Connection *c = new Connection(serverSocket, m_requestHandler, this);
m_connections.insert(c);
connect(serverSocket, &QAbstractSocket::disconnected, this, [c, this]() { removeConnection(c); });
}
void Server::removeConnection(Connection *connection)
{
m_connections.remove(connection);
connection->deleteLater();
m_connections.append(c);
}
void Server::dropTimedOutConnection()
{
QMutableSetIterator<Connection *> i(m_connections);
QMutableListIterator<Connection *> i(m_connections);
while (i.hasNext()) {
Connection *connection = i.next();
if (connection->hasExpired(KEEP_ALIVE_DURATION)) {
connection->deleteLater();
auto connection = i.next();
if (connection->isClosed() || connection->hasExpired(KEEP_ALIVE_DURATION)) {
delete connection;
i.remove();
}
}
@@ -153,9 +146,9 @@ QList<QSslCipher> Server::safeCipherList() const
const QStringList badCiphers = {"idea", "rc4"};
const QList<QSslCipher> allCiphers = QSslSocket::supportedCiphers();
QList<QSslCipher> safeCiphers;
for (const QSslCipher &cipher : allCiphers) {
foreach (const QSslCipher &cipher, allCiphers) {
bool isSafe = true;
for (const QString &badCipher : badCiphers) {
foreach (const QString &badCipher, badCiphers) {
if (cipher.name().contains(badCipher, Qt::CaseInsensitive)) {
isSafe = false;
break;

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