Compare commits

..

614 Commits

Author SHA1 Message Date
sledgehammer999
78c5d1c12f Bump to v3.3.0 2015-11-29 21:57:06 +02:00
sledgehammer999
26fb54299b Update Transifex config file. 2015-11-29 21:54:06 +02:00
sledgehammer999
8ad82fc748 Update Changelog. 2015-11-29 21:51:14 +02:00
sledgehammer999
6e5aab7e98 Sync translations from Transifex and run lupdate. 2015-11-29 21:43:11 +02:00
sledgehammer999
fd39efd846 Fix cases where the fastresume was wrongly overwritten when in 'Missing Files' status. Closes #3602. 2015-11-29 18:40:24 +02:00
sledgehammer999
86dba7bd21 Don't rebind listen port on 'network configuration changed' signal when we listen on any address. Closes #4139. 2015-11-29 14:30:49 +02:00
sledgehammer999
ac3b01e02e Merge pull request #4177 from ngosang/webui_color
[WebUI] Change colors in selected filters and torrents.
2015-11-29 06:25:47 -06:00
sledgehammer999
c267036427 Merge pull request #4178 from ngosang/torrentzup
[searchengine] Update Torrentz trackers
2015-11-29 06:16:00 -06:00
sledgehammer999
0a0c8f307b Merge pull request #4175 from glassez/seq_dl
Prevent return cached "sequential download" state. Closes #4167.
2015-11-29 06:15:22 -06:00
Vladimir Golovnev (Glassez)
e804e6e91a Prevent return cached "sequential download" state. Closes #4167. 2015-11-26 15:09:11 +03:00
Vladimir Golovnev (Glassez)
67e90d8d2a Make setSequentialDownload/setFirstLastPiecePriority independent. 2015-11-26 15:08:01 +03:00
sledgehammer999
88abe2baff Fix shutdown dialog. Closes #4171. 2015-11-25 18:30:43 +02:00
sledgehammer999
23748547a2 Merge pull request #4150 from glassez/coding_style
Improve CODING_GUIDELINES.md.
2015-11-23 10:19:50 -06:00
sledgehammer999
0b68c2356c Merge pull request #4111 from dpeukert/master
WebUI: Change selected color
2015-11-23 10:18:03 -06:00
sledgehammer999
0aaf4d1050 Update Changelog. 2015-11-22 22:08:33 +02:00
sledgehammer999
ce535c9492 Bump version status. 2015-11-22 22:08:21 +02:00
sledgehammer999
3e6d76245c Bump WebUI API_VERSION. 2015-11-22 22:08:16 +02:00
sledgehammer999
18f3517efa New translation: Esperanto
Also re-run lupdate.
2015-11-22 22:08:10 +02:00
sledgehammer999
09e85900d7 Sync translations from Transifex and run lupdate. 2015-11-22 22:08:04 +02:00
sledgehammer999
6e09028682 Switch to Qt5 by default. 2015-11-22 22:07:59 +02:00
Vladimir Golovnev (Glassez)
59427ed6af Improve CODING_GUIDELINES.md. 2015-11-21 11:25:14 +03:00
sledgehammer999
340288f308 Merge pull request #4114 from glassez/fix-4105
Fix default save path for magnet. Closes #4105.
2015-11-18 11:36:12 -06:00
sledgehammer999
b76428420e Merge pull request #4136 from glassez/remove_labels
Fix 'Remove unused labels'. Closes #4066.
2015-11-18 11:07:03 -06:00
sledgehammer999
22d9427e20 Fix reordering of first column with Qt5. Closes #2835. 2015-11-18 18:14:24 +02:00
sledgehammer999
2e3cce6755 Merge pull request #4135 from Chocobo1/speedplot_color
Fix Speed graph legend is illegible on dark background. Closes #4134.
2015-11-18 04:14:32 -06:00
Vladimir Golovnev (Glassez)
3f9b568808 Fix 'Remove unused labels'. Closes #4066. 2015-11-18 12:52:06 +03:00
Chocobo1
a74bac20c4 Fix Speed graph legend is illegible on dark background. Closes #4134. 2015-11-18 14:41:29 +08:00
sledgehammer999
ee6b968f2f Don't save/load the session state. We configure it anyway. 2015-11-17 23:03:56 +02:00
sledgehammer999
00fae05507 Don't ask the user questions in nox build when in non-interactive mode. Closes #3875. 2015-11-17 23:00:33 +02:00
sledgehammer999
9718b7d9ba New view for errored torrents. 2015-11-17 19:29:05 +02:00
sledgehammer999
bf0319f7b2 Fix status string for errored torrents. 2015-11-17 19:18:50 +02:00
sledgehammer999
5b232528cc Fixup previous commit. 2015-11-16 02:58:41 +02:00
dsimakov
1f17a7836d 1. In option window add column 'download path' for watched folders and enlarge heigth.
2. Change logic checkbox in column 'download here': if it checked,
   then torrent file will download to watchdir, if state is unchecked,
   will be use download path from next column.
2015-11-16 02:45:23 +02:00
Vladimir Golovnev (Glassez)
e183c12bed Fix default save path for magnet. Closes #4105. 2015-11-14 09:38:01 +03:00
Daniel Peukert
3901f1555d WebUI: Change selected color
The selected color was little bit too close to the progress bar color.
2015-11-14 00:23:33 +01:00
sledgehammer999
84f6a82d98 Merge pull request #4062 from glassez/speedup
Some TransferListWidget speedup.
2015-11-13 11:14:43 -06:00
sledgehammer999
100cff1738 Merge pull request #3856 from ngosang/fix_search
[searchengine] Fix invalid plugin message and detect new plugin URL from clipboard
2015-11-10 03:15:59 -06:00
sledgehammer999
d12ab5c048 Sync translations from Transifex and run lupdate. 2015-11-10 01:13:25 +02:00
sledgehammer999
055ad080a1 Pass the alertMask to the session constructor to not lose initial alerts. 2015-11-10 00:23:59 +02:00
sledgehammer999
c771703c34 Merge pull request #3932 from Chocobo1/refactor
Refactor
2015-11-09 15:29:19 -06:00
sledgehammer999
cf1c934083 Merge pull request #3961 from Chocobo1/comment_click
Make URL in "Add Torrent File..." clickable
2015-11-09 15:27:56 -06:00
sledgehammer999
c40bab0555 Merge pull request #4094 from ngosang/webui_ipv6
[WebUI] Patch mootools-more to fix IPv6 problem. Closes #3621
2015-11-09 11:23:25 -06:00
Chocobo1
fadb208299 Fix compile warning:
warning: enumeration value 'Unknown' not handled in switch [-Wswitch]
2015-11-09 16:14:29 +08:00
Chocobo1
a6d2f5186f Avoid falling through the switch case 2015-11-09 16:10:04 +08:00
ngosang
80f7e7868d [searchengine] Update Torrentz trackers 2015-11-09 04:10:57 +01:00
ngosang
40bdeb6c2d [WebUI] Change colors in selected filters and torrents. 2015-11-09 03:38:37 +01:00
ngosang
e0be09dd81 [WebUI] Patch mootools-more to fix IPv6 problem. Closes #3621 2015-11-09 01:57:40 +01:00
sledgehammer999
45dbfe80a1 Merge pull request #4035 from Chocobo1/reduce_cache
Reduce max value of "Disk cache size"
2015-11-08 04:26:22 -06:00
Chocobo1
db45c11d84 Reduce max value of "Disk cache size" to 1536MB. Closes to #4028. 2015-11-08 13:58:28 +08:00
sledgehammer999
80a9896a4e Merge pull request #4080 from ngosang/privacy
Change personal email
2015-11-07 18:09:50 -06:00
ngosang
9fefdc0fbb Change personal email 2015-11-07 23:40:11 +01:00
sledgehammer999
a16d0f8d28 Don't connect to "any interface" when the configured network interface is missing. Closes #3943, #2741, #1159, #844 and #143. 2015-11-07 02:06:07 +02:00
sledgehammer999
472fff06dc Merge pull request #3984 from glassez/root_path
Fix TorrentHandle path methods. Closes #3847.
2015-11-06 16:03:48 -06:00
Vladimir Golovnev (Glassez)
91ffbfcf68 Some TransferListWidget speedup.
Handle data changed event for all torrents at once.
2015-11-06 08:38:09 +03:00
sledgehammer999
5cf976bbb2 Better fix for e6b7a429ea. 2015-11-04 23:37:35 +02:00
sledgehammer999
e6b7a429ea Fix reporting of tracker status. Closes #3101. 2015-11-04 19:13:09 +02:00
sledgehammer999
12072e2b69 Always apply filter for manually banned IPs. Related #3988. 2015-11-04 17:15:37 +02:00
sledgehammer999
4cecb585bc Merge pull request #3444 from ngosang/webui_labels
[Web UI] Labels implementation
2015-11-03 16:31:05 -06:00
sledgehammer999
66ce5c2557 Merge pull request #3332 from ngosang/addtrackers2
Automatically add trackers to new downloads. Closes #262
2015-11-02 10:51:59 -06:00
sledgehammer999
f7f23d2ae9 Merge pull request #3809 from ngosang/webui_optim
[Web UI] Code cleanup and little change in contextual menu
2015-11-01 17:38:55 -06:00
sledgehammer999
e204562f4d Merge pull request #4037 from glassez/label
Fix 'Append label to save path'. Closes #4031.
2015-11-01 11:12:16 -06:00
Vladimir Golovnev (Glassez)
c38987fc03 Provide torrent paths to external program. 2015-11-01 17:09:15 +03:00
Vladimir Golovnev (Glassez)
501ab07024 Fix TorrentHandle path methods. Closes #3847. 2015-11-01 17:09:09 +03:00
sledgehammer999
d0ebe08bf5 Merge pull request #3604 from Chocobo1/deletion
Don't remove torrent contents parent folder, even it is empty.
2015-11-01 07:35:03 -06:00
Chocobo1
4fcd107ff3 Don't remove torrent contents parent folder, even it is empty. Closes #2244. 2015-11-01 21:01:55 +08:00
Vladimir Golovnev (Glassez)
25feee2366 Fix 'Append label to save path'. Closes #4031. 2015-11-01 11:26:57 +03:00
sledgehammer999
a39ce57094 Merge pull request #4022 from glassez/vector
Fix PieceAvailabilityBar::intToFloatVector(). Closes #3937.
2015-10-29 15:59:29 -05:00
Vladimir Golovnev (Glassez)
f7150edd44 Fix DownloadedPiecesBar::bitfieldToFloatVector(). 2015-10-29 14:49:01 +03:00
Vladimir Golovnev (Glassez)
be78188691 Fix PieceAvailabilityBar::intToFloatVector(). Closes #3937. 2015-10-29 14:46:43 +03:00
sledgehammer999
c75725e2d8 Fix printing of avg download speed in General button. Closes #4013. 2015-10-28 01:47:01 +02:00
sledgehammer999
9b6122c328 Fix corner case of reseting 'm_hasSeedStatus' in 3a29d70dd5. 2015-10-28 01:46:53 +02:00
sledgehammer999
99ba8a6a53 Merge pull request #3990 from naikel/payload_fix
Changed payload functions from int to qlonglong in TorrentHandle class
2015-10-27 03:48:22 -05:00
sledgehammer999
3a29d70dd5 Correctly set the 'm_hasSeedStatus' parameter on different situations. 2015-10-26 00:53:04 +02:00
Naikel Aparicio
2a2c947602 Changed payload functions from int to qlonglong in TorrentHandle class 2015-10-25 14:29:12 -04:30
sledgehammer999
cd3dc3d645 Merge pull request #3343 from Chocobo1/tx_list
Minor style change in transfer list & filters
2015-10-25 10:09:40 -05:00
sledgehammer999
f74c68e121 React again to finished torrents when previously unselected files have finished downloading. 2015-10-25 17:03:22 +02:00
sledgehammer999
bfd30dcabc Don't put finished torrents in seed_mode.
Seed mode has special function in libtorrent. It is used to skip hash checking when adding a torrent and consider it complete.
2015-10-25 17:03:14 +02:00
Chocobo1
5d3ba06e9d Use thin border for transfer list 2015-10-25 14:06:06 +08:00
Chocobo1
e275c3ba52 Add helper function: Get DPI scaled icon size (device-dependent) 2015-10-25 14:06:06 +08:00
Chocobo1
3335a111e1 Use a larger spacing between filters
Simplify code
2015-10-25 14:06:06 +08:00
sledgehammer999
f7c8a499d5 Unload the GeoIP db when disabled. 2015-10-25 02:54:27 +03:00
sledgehammer999
ad7ad8f596 Faster GeoIP lookups.
QCache results in speed decrease.
See https://github.com/qbittorrent/qBittorrent/pull/3488#issuecomment-124731983
2015-10-25 02:54:19 +03:00
sledgehammer999
ef5b3b90c3 Don't save the GeoIP nodes beforehand.
It saves a lot of memory and isn't much faster.
2015-10-25 02:54:11 +03:00
sledgehammer999
787b824d90 Merge pull request #3323 from Chocobo1/prop_bar
Availability bar, progress bar, button group improvements
2015-10-24 06:45:12 -05:00
Chocobo1
7e6dfa759c Replace horizontal line with border 2015-10-22 17:34:22 +08:00
Chocobo1
c6a6f85a5e Use theme color for background in PropertiesWidget 2015-10-22 17:34:22 +08:00
Chocobo1
421b45c553 Add tooltips/legend for availability bar & progress bar 2015-10-22 17:34:22 +08:00
sledgehammer999
0507876080 Merge pull request #3967 from glassez/webui
Cast MaxRatioAction to int when store as JSON. Closes #3939.
2015-10-19 15:15:45 -05:00
Vladimir Golovnev (Glassez)
52db762677 Cast MaxRatioAction to int when store as JSON. Closes #3939. 2015-10-19 21:14:41 +03:00
sledgehammer999
94037cd017 Merge pull request #3949 from netswap/patch-1
[german.nsi] Little fixes
2015-10-19 11:21:56 -05:00
Chocobo1
a16de62103 Make URL in "Add Torrent File..." clickable. Closes #3928. 2015-10-19 11:57:03 +08:00
sledgehammer999
df8def02f5 Merge pull request #3933 from glassez/streamops
Register stream operators for enum classes. Closes #3921.
2015-10-18 15:09:59 -05:00
sledgehammer999
d60f2fc7df Fix another potential crash when memory allocation failed.
See commit e95fce3084.
Related issues #3877 and #2673.
2015-10-17 18:21:33 +03:00
sledgehammer999
cc9ffc4767 Use the actual function names for debug logging. 2015-10-17 17:41:53 +03:00
sledgehammer999
f6a620cf6e Merge pull request #3951 from glassez/const
Fix possible compilation error. Closes #3947.
2015-10-16 04:55:23 -05:00
Vladimir Golovnev
a7cf8cea3f Fix possible compilation error. Closes #3947. 2015-10-16 12:02:47 +03:00
netswap
4cec06e67c [german.nsi] Little fixes
Line 6: "auf dem" instead of "am" (oriented at https://support.microsoft.com/de-de/kb/140443; more commonly used)
Line 41: "aus" instead of "in" (makes more sense imo)

Anyone else fluent in German can discuss for sure. Only because I changed something it does not mean it is *completely* right, eh? ;-)
2015-10-15 22:38:36 +02:00
sledgehammer999
41c953de46 Merge pull request #3938 from glassez/path
Use default save path if save path is not set.
2015-10-14 18:43:43 -05:00
Vladimir Golovnev (Glassez)
986bb1a8ac Use default save path if save path is not set. 2015-10-13 21:58:25 +03:00
Vladimir Golovnev
a7ff38d389 Register stream operators for enum classes. Closes #3921. 2015-10-13 10:39:17 +03:00
Chocobo1
f530bb7537 Fix availability label & progress label clipped on high DPI displays, closes #3237. 2015-10-12 15:34:22 +08:00
Chocobo1
b5adbaef78 Fix availability bar & progress bar height being too small on high DPI displays 2015-10-12 15:12:42 +08:00
sledgehammer999
4a271d358f Merge pull request #3918 from glassez/winfix
Fix compilation on Windows.
2015-10-11 16:26:46 -05:00
Vladimir Golovnev (Glassez)
d9e51c220e Fix compilation on Windows. 2015-10-11 15:07:20 +03:00
sledgehammer999
d413c2061c Merge pull request #3859 from glassez/simplify
Simplify Session/TorrentHandle classes.
2015-10-11 04:19:51 -05:00
sledgehammer999
9646794bb1 Merge pull request #3844 from glassez/added_time
Use libtorrent::torrent_status::added_time (Closes #3764).
2015-10-11 04:14:30 -05:00
Vladimir Golovnev (Glassez)
d40495a4be Simplify Session/TorrentHandle classes. 2015-10-11 08:05:57 +03:00
Vladimir Golovnev (Glassez)
b63a68c9db Use libtorrent::torrent_status::added_time (Closes #3764). 2015-10-11 07:58:56 +03:00
sledgehammer999
1ba1f90058 Merge pull request #3845 from glassez/drop_unused
Drop unused TorrentHandle methods.
2015-10-10 13:06:10 -05:00
sledgehammer999
8d025949d9 Merge pull request #3838 from glassez/wswitch
Fix compiler warnings (Closes #3826).
2015-10-10 13:01:27 -05:00
sledgehammer999
4291a08d47 Merge pull request #3649 from glassez/savepathlabel
Fix 'Append label to save path'. Closes #3495.
2015-10-10 12:45:20 -05:00
sledgehammer999
3eac05b229 Fix broken .desktop file icon for some locales. See #3905. 2015-10-09 17:53:26 +03:00
sledgehammer999
e39f8fafb1 Bump WebUI API_VERSION. 2015-10-09 16:46:20 +03:00
sledgehammer999
50b9438fb6 Cleaner way to disable linux qt5 builds on Travis. 2015-10-09 06:01:14 +03:00
sledgehammer999
357dfca3e0 Optimize text color for dark themes v2. Closes #3815. 2015-10-09 02:05:15 +03:00
sledgehammer999
8f8218c515 Fix Qt5 nox build on non-Windows. 2015-10-07 21:29:21 +03:00
sledgehammer999
10e3009c46 Enable Qt5 compilation for OS X on Travis. 2015-10-07 21:29:16 +03:00
sledgehammer999
cc5a737836 Fix Coverity Scan builds. 2015-10-05 23:39:43 +03:00
sledgehammer999
19ad58c394 Merge pull request #3685 from glassez/cpp11
Add C++11 support.
2015-10-05 11:53:42 -05:00
sledgehammer999
8a905bed5d Merge pull request #3879 from Chocobo1/avail_bar_crash
Fix potential crash when memory allocation failed. Closes #3877.
2015-10-05 11:30:23 -05:00
sledgehammer999
f781cc18a6 Merge pull request #3852 from ngosang/filemanagers
Fix Konqueror detection in Plasma (KDE5)
2015-10-05 04:09:57 -05:00
sledgehammer999
db174614f2 Add forum link in README. Closes #3853. 2015-10-04 22:30:44 +03:00
sledgehammer999
b9a061680d Fix broken donation link. Closes #3771. 2015-10-04 22:26:56 +03:00
sledgehammer999
63df3090d5 Fix python detection when the 'Anaconda' software is installed. Closes #3731. 2015-10-04 12:10:07 +03:00
sledgehammer999
ff8ff72eab Merge pull request #3863 from netswap/patch-1
[german.nsi] Added letter "p"
2015-10-04 03:37:30 -05:00
sledgehammer999
8b547644b0 Merge pull request #3165 from Chocobo1/rss_sort
Sort labels in RSS Downloader dialog
2015-10-03 18:52:46 -05:00
Chocobo1
8605c4d4d3 Follow project coding style. Issue #2192. 2015-10-02 04:17:27 +08:00
Chocobo1
e95fce3084 Fix potential crash when memory allocation failed. Closes #3877. 2015-10-02 04:08:24 +08:00
Chocobo1
cf91685f6f Sort labels in RSS Downloader dialog, closes #3140. 2015-09-28 00:30:43 +08:00
netswap
e3e3f9a745 Added letters
The letter "p" was missing in "Dateiverknüpfung" in line 47 & 49
2015-09-26 15:05:36 +02:00
ngosang
6a1497de92 [searchengine] Detect new plugin URL from clipboard 2015-09-25 11:15:41 +02:00
ngosang
fc65ba4ced [searchengine] Fix invalid plugin message 2015-09-24 18:17:50 +02:00
ngosang
73fb0a6309 Fix Konqueror detection in Plasma (KDE5) 2015-09-24 15:53:44 +02:00
Vladimir Golovnev (Glassez)
2a411987db Bump minimum supported version of gcc to 4.8. 2015-09-24 13:26:25 +03:00
sledgehammer999
79617949c1 Merge pull request #3849 from ngosang/fix_rss_crash
Fix RSS crash when deleting RSS feeds. Closes #3846
2015-09-23 17:04:45 -05:00
ngosang
c3921ce2fe Fix RSS crash when deleting RSS feeds. Closes #997, #2152, #2461, #3718, #3747, #3766, #3806, #3814, #3829 and #3846. 2015-09-23 23:51:39 +02:00
Vladimir Golovnev (Glassez)
228f51fff9 Drop unused method TorrentHandle::firstFileSavePath(). 2015-09-23 21:55:04 +03:00
Vladimir Golovnev (Glassez)
08ee439a47 Drop unused method TorrentHandle::savePathParsed(). 2015-09-22 20:39:09 +03:00
Vladimir Golovnev (Glassez)
1a67282dd3 Fix Qt4 qmake warning (unknown QT: concurrent). 2015-09-22 19:34:07 +03:00
Vladimir Golovnev (Glassez)
d2f1216987 Fix compiler warnings (Closes #3826). 2015-09-21 11:45:40 +03:00
Vladimir Golovnev (Glassez)
b519700e33 Use c++11 enum classes instead of macros. 2015-09-18 08:33:22 +03:00
Vladimir Golovnev (Glassez)
12d9898b5d Enable c++11 support. 2015-09-18 08:33:12 +03:00
sledgehammer999
ef39fb0709 Merge pull request #3811 from ngosang/rss_refresh
[RSS] Removes refresh message when adding a new feed
2015-09-17 18:09:59 -05:00
sledgehammer999
f068f63f0d Merge pull request #3745 from cbodley/webui-savepath
RFC: [Web UI] add save_path to /query/torrents and /sync/maindata
2015-09-17 17:14:44 -05:00
sledgehammer999
57ca831d4d Merge pull request #3730 from Gelmir/rss_save
Couple o' fixes to RSS
2015-09-17 17:02:27 -05:00
ngosang
093c5d84d2 [RSS] Removes refresh message when adding a new feed 2015-09-17 19:17:52 +02:00
ngosang
e922275c72 [Web UI] Clean up JavaScript code 2015-09-17 17:48:38 +02:00
ngosang
52ff53b0b0 [Web UI] Reorder "Super seeding mode" option in right click menu 2015-09-17 17:22:09 +02:00
Chocobo1
65d3ca8c3f Capitalize items 2015-09-17 18:08:12 +08:00
Chocobo1
a16c264aa3 RSS Downloader dialog cleanup 2015-09-17 18:08:12 +08:00
sledgehammer999
4642a35de7 Don't limit the number of torrents that can be announced to the tracker/dht/lsd. Closes #3473. 2015-09-16 22:03:20 +03:00
sledgehammer999
50822a7476 Merge pull request #3071 from ppolewicz/interface_bind_fixes
Interface bind fixes
2015-09-16 13:04:52 -05:00
Pawel Polewicz
f108e67dcc Call setListeningPort() when state of network interface changes (closes qbittorrent/qBittorrent#475, closes qbittorrent/qBittorrent#3072) 2015-09-16 14:32:49 +02:00
Pawel Polewicz
fb22940639 Small refactor in Session::setListeningPort() 2015-09-16 14:32:49 +02:00
ngosang
9c7bb08a03 Automatically add trackers to new downloads. 2015-09-16 11:43:57 +02:00
sledgehammer999
b4680e82b7 Merge pull request #3765 from jsayol/patch-1
Allow adding torrent link from Torcache
2015-09-15 18:52:53 -05:00
sledgehammer999
cbf683878a Show current label in the torrent context menu. Closes #3776. 2015-09-16 02:43:48 +03:00
Josep Sayol
fd5d3d0a48 Allow adding torrent link from Torcache
Recent changes in Torcache prevent adding (or drag-and-dropping) a torrent link into qBittorrent. Modifying DownloadManager to always spoof the HTTP Referer header to the file itself being downloaded solves this.
2015-09-16 05:08:53 +07:00
sledgehammer999
5cb022c7b1 Merge pull request #3736 from Chocobo1/option
Cleanup in options_imp
2015-09-15 17:03:45 -05:00
sledgehammer999
145950e766 Optimize text color for dark themes. Closes #3633. 2015-09-15 23:23:49 +03:00
sledgehammer999
8bde7d45b8 Try to avoid loading a corrupted configuration file. Also log errors encountered while saving/loading the configuration. Closes #3503. 2015-09-14 02:23:13 +03:00
Chocobo1
e0935fe14f Follow project coding style. Issue #2192. 2015-09-10 15:24:38 +08:00
Chocobo1
c27aa7723e Options GUI layout cleanups: Speed Page
Move uTP options to it's own section
2015-09-10 15:24:38 +08:00
Casey Bodley
87b26a8dcc webui: add save_path to /query/torrents
Signed-off-by: Casey Bodley <cbodley@gmail.com>
2015-09-07 16:25:07 -04:00
sledgehammer999
0b2b07e98e Sync translations from Transifex and run lupdate. 2015-09-04 23:30:39 +03:00
sledgehammer999
581d544f61 Fix typos. Make ìTP untranslatable. Use American variation of words. Closes #3654. 2015-09-04 23:14:02 +03:00
sledgehammer999
aa5fbd461f Merge pull request #3734 from ngosang/rss_sidebar
Fix RSS panel position not saved. Closes #3732
2015-09-04 13:53:05 -05:00
sledgehammer999
5394b77086 Merge pull request #3725 from Chocobo1/osx
TravisCI: build on osx
2015-09-03 03:24:27 -05:00
Chocobo1
7028c2712a Reorder code in options_imp::loadOptions() according to GUI layout 2015-09-03 15:19:05 +08:00
Chocobo1
89be63da02 TravisCI: build on osx 2015-09-03 12:51:54 +08:00
ngosang
4f504f597d Fix RSS panel position not saved 2015-09-03 04:45:47 +02:00
ngosang
a9e9a9c835 [Web UI] Changes in labels implementation 2015-09-03 03:16:07 +02:00
Felipe Barriga Richards
4ae2f6c33b webui (js): feature: Added complete support for labels (add/set/reset/display/filter) #648
Changes:
- added list of labels on the lower-left corner
- added support to add/set/reset labels on context menu
- added support to filter torrents by label
2015-09-03 03:16:07 +02:00
Felipe Barriga Richards
76d93c23b7 webui (c++): feature: added labels support. #648 2015-09-03 03:16:07 +02:00
sledgehammer999
9d051ea523 Merge pull request #3713 from ngosang/translate_countries
Allows translation of country names. Closes #3710
2015-09-02 16:48:14 -05:00
sledgehammer999
ff279681ac Merge pull request #3599 from pmzqla/strings
Misc translatable strings changes
2015-09-02 16:47:20 -05:00
Gabriele
5cc5552d9b Use infinity symbol rather than -1 for nb_connections 2015-09-02 23:34:17 +02:00
Gabriele
42c74f9553 Avoid concatenation when dealing with translatable strings
Concatenation could be problematic with RTL languages.
2015-09-02 23:34:17 +02:00
Gabriele
420fa82e8d Put some string placeholders between quotes 2015-09-02 23:26:19 +02:00
sledgehammer999
70f2086202 Merge pull request #3567 from ngosang/rssfixes
[RSS] Several changes in RSSs. Closes #3560
2015-09-02 14:24:25 -05:00
ngosang
ee21562426 [RSS] Handle more types of RSS feeds 2015-09-02 20:10:44 +02:00
ngosang
b6c707c080 [RSS] Simplify string translation 2015-09-02 20:00:38 +02:00
ngosang
2eaeead67c [RSS] Allow multiple selection in RSS torrents list 2015-09-02 19:36:45 +02:00
ngosang
7c7da44622 [RSS] Don't hide the elements in Unread list when clicked 2015-09-02 19:12:39 +02:00
ngosang
7c6da30705 [RSS] More precise message and code simplification in RSS feeds deletion 2015-09-02 19:12:32 +02:00
ngosang
2955bb5488 [RSS] Improve error handling when a RSS feed doesn't contain torrents 2015-09-02 19:06:33 +02:00
ngosang
b78ccf289e [RSS] Fix contextual menu in RSS torrents list 2015-09-02 19:01:59 +02:00
ngosang
b9b7786477 [RSS] Trim elements text in RSS articles 2015-09-02 18:51:39 +02:00
ngosang
c3592304b6 [RSS] Handle magnet links as torrents instead of news URLs. Closes #3560 2015-09-02 18:51:39 +02:00
Nick Tiskov
2442411a5e Fix: Adding RSS rule with a new label doesn't add this label to UI. 2015-08-31 02:12:02 +03:00
Nick Tiskov
f5c0cddea5 Fix: Label changes to first item in RSS rule list are forgotten, because checkRegex calls updateMustLineValidity, which saves the rule before new label can be applied. 2015-08-31 01:48:30 +03:00
sledgehammer999
51e0e485f4 Merge pull request #3592 from pmzqla/favicon
Try to download favicon.png when the download of favicon.ico fails
2015-08-30 15:35:53 -05:00
Gabriele
3889b4c101 Try to download favicon.png when the download of favicon.ico fails
This was done only when favicon.ico couldn't be decoded, but not when
favicon.ico could not be downloaded at all.
2015-08-30 22:28:06 +02:00
sledgehammer999
247ba02bb8 Merge pull request #3586 from pmzqla/configure
configure: don't depend on GNU sed
2015-08-30 13:52:34 -05:00
sledgehammer999
25c6d8bf6b Merge pull request #3561 from pmzqla/proxy-torrent
Add an option to allow the use of proxies only for torrents
2015-08-30 12:38:16 -05:00
sledgehammer999
cf72318d74 Merge pull request #2633 from Chocobo1/my_dev2
Fix wrong default download directory in Windows. Closes #2625.
2015-08-30 10:59:24 -05:00
Gabriele
a8c05ca02e Add https_proxy env variable
This forces Python to use the HTTP proxy for HTTPS connections.
2015-08-30 17:46:12 +02:00
Gabriele
1c8abd5c3b Add an option to allow the use of proxies only for torrents
Closes #2701.
2015-08-30 17:46:11 +02:00
Chocobo1
6ebe3897fb Fix wrong default download directory in Windows. Closes #2625. 2015-08-30 23:45:34 +08:00
sledgehammer999
9faa44eabf Merge pull request #3581 from pmzqla/redirect
DownloadManager: fix downloads after a redirection
2015-08-30 09:43:18 -05:00
sledgehammer999
f81ffdb78e Merge pull request #3644 from Chocobo1/graph_btn
Change "Select Graphs" from QToolButton to QComboBox
2015-08-30 08:59:00 -05:00
Chocobo1
2997c0fd1e Change "Select Graphs" from QToolButton to QComboBox 2015-08-30 21:38:05 +08:00
sledgehammer999
193d273f00 Merge pull request #3636 from Chocobo1/moveOption_del
Move option "Confirm torrent deletion" to Behavior page
2015-08-30 08:34:54 -05:00
Chocobo1
e54cd8499e Move option "Confirm torrent deletion" to Behavior page 2015-08-30 21:28:16 +08:00
ngosang
c984902fbf Allows translation of country names 2015-08-30 15:09:15 +02:00
sledgehammer999
45cbf4bf25 Merge pull request #3481 from Chocobo1/moveOption
Move option "Ignore transfer limits on local network" to Speed page
2015-08-30 07:58:30 -05:00
Chocobo1
2204f27de1 Follow project coding style. Issue #2192. 2015-08-30 20:35:33 +08:00
sledgehammer999
735b1cc6b9 Merge pull request #3470 from ngosang/reorder_buttons
Change Queue buttons order in the Toolbar (GUI & Web UI)
2015-08-30 07:10:20 -05:00
sledgehammer999
a0da4a844c Merge pull request #3625 from Chocobo1/native_path
Use native path separators
2015-08-30 07:07:58 -05:00
sledgehammer999
45ef98b077 Update ax_boost_base.m4 to fix ppc64le detection. 2015-08-30 04:50:30 +03:00
sledgehammer999
ef7de49ec8 Fix dolphin detection for KDE5. 2015-08-29 23:49:14 +03:00
sledgehammer999
e937344761 Fix a bug with highlighting selected file on Windows. Closes #3185. 2015-08-29 23:49:09 +03:00
sledgehammer999
f3c3912923 Merge pull request #2544 from pmzqla/select-destination
Select the file of single file torrents when opening the destination folder
2015-08-29 12:49:52 -05:00
Gabriele
e728710430 Select the file of single file torrents when opening destination folder
Also, add the support for Nautilus (Gnome 3), Caja and Nemo.
2015-08-29 16:09:22 +02:00
sledgehammer999
ddd6533812 Merge pull request #3701 from onto/master
SpeedPlotView: fix render graphs with zero speed
2015-08-29 07:28:02 -05:00
Anton Lashkov
0d74131edd SpeedPlotView: fix render graphs with zero speed 2015-08-29 11:24:51 +04:00
Chocobo1
cf3a87ed55 Use native path separators, fixup of 030dd9e, 3baec1c. 2015-08-29 14:17:21 +08:00
sledgehammer999
632cba8b30 Merge pull request #3638 from Fale/patch-1
Fix minimum libtorrent-rasterbar version
2015-08-17 15:49:46 -05:00
Vladimir Golovnev (Glassez)
0afa4d260c Fix 'Append label to save path'. Closes #3495. 2015-08-17 18:37:00 +03:00
Fabio Alessandro Locati
3f2303a479 Fix minimum libtorrent-rasterbar version
as title
2015-08-17 10:13:20 +02:00
Gabriele
7bfa847d01 configure: don't depend on GNU sed
Closes #3169.
2015-08-07 00:11:42 +02:00
sledgehammer999
331219dda8 Write BOM to german.nsi. Closes #3574, #3566 2015-08-05 23:24:21 +03:00
Gabriele
b2df917011 DownloadManager: fix downloads after a redirection
Closes #3580.
2015-08-05 21:41:57 +02:00
Chocobo1
b727ce3b29 Remove filters frame 2015-08-05 12:56:23 +08:00
Chocobo1
0e1eaa518b Alignment cleanup 2015-08-05 12:56:23 +08:00
sledgehammer999
f893131b8d Less verbose compilation output. Closes #3565. 2015-08-04 19:17:01 +03:00
sledgehammer999
2ec1d9e39e New translation: Slovenian
Also re-run lupdate.
2015-08-04 19:14:02 +03:00
sledgehammer999
bd2f9e436c Sync translations from Transifex and run lupdate. 2015-08-04 19:03:32 +03:00
sledgehammer999
ea38e4da4d Merge pull request #2699 from pmzqla/copyurl-search
Add "Copy description page URL" button in search tab
2015-08-04 18:45:31 +03:00
Gabriele
4d66a0929c Add "Copy description page URL" button in search tab
Closes #2371.
2015-08-04 11:18:46 +02:00
sledgehammer999
0520f01510 Merge pull request #3550 from Chocobo1/title_fix
Add back "qBittorrent" in program updater title, closes #3549.
2015-08-04 11:53:03 +03:00
Chocobo1
deaf322740 Add back "qBittorrent" in program updater title, closes #3549. 2015-08-04 13:07:14 +08:00
sledgehammer999
929cd30e33 Merge pull request #3517 from glassez/strict_aliasing
Fix strict-aliasing warning.
2015-08-03 02:50:22 +03:00
sledgehammer999
eef2a0a200 Merge pull request #3537 from ngosang/fixwarnings
Fix 3 compiler warnings
2015-08-02 16:10:24 +03:00
ngosang
fbb47ce08f Fix 3 compiler warnings 2015-08-02 14:22:47 +02:00
sledgehammer999
f746760ccf Merge pull request #3505 from pmzqla/search-close
searchengine: fix crash when a tab with a running search is closed
2015-08-02 15:21:30 +03:00
Gabriele
67c0f47928 searchengine: remove size constraints to search button 2015-08-02 14:04:11 +02:00
Gabriele
7c00e80f7a searchengine: use kill() instead of terminate() on Windows 2015-08-02 14:04:11 +02:00
Gabriele
3a9cf70228 searchengine: use a single string for the search results number label 2015-08-02 14:04:11 +02:00
Gabriele
0f35bac605 searchengine: don't use strings to determine the status of search processes
'&' symbols are dynamically added to strings, making comparisons
unreliable.
2015-08-02 14:04:07 +02:00
Gabriele
1b24feb4f4 searchengine: drop unused flag and related code 2015-08-02 13:53:12 +02:00
Gabriele
ee8a492954 searchengine: fix crash when closing tab with running search
If a tab is closed, the search process gets terminated. This can take
a while and by the time searchFinished() is executed, activeSearchTab
is null, leading to a crash. Fix this by waiting for the process to
terminate and make sure activeSearchTab is not null when used.
2015-08-02 13:49:42 +02:00
sledgehammer999
e3cb9de365 Bump minimum libtorrent version required to 1.0.6. 2015-07-31 23:29:59 +03:00
sledgehammer999
a217988dbb Merge pull request #3515 from glassez/parser
Fix HTTP header parsing. Closes #3511.
2015-07-31 02:38:04 +03:00
sledgehammer999
81c6de48dc Don't use geoip for Travis CI. 2015-07-30 23:45:35 +03:00
sledgehammer999
1217d8d021 Merge pull request #3497 from Chocobo1/ext_param_early
Fix "Run External Program Launches too Early" issue
2015-07-30 11:28:08 +03:00
sledgehammer999
3362766cb5 Merge pull request #3512 from Chocobo1/travis
Migrate TravisCI to container-based infrastructure
2015-07-30 11:27:29 +03:00
Vladimir Golovnev (Glassez)
34da3e653d Fix strict-aliasing warning. 2015-07-30 09:38:25 +03:00
Vladimir Golovnev (Glassez)
ddb5c0052d Fix HTTP header parsing. Closes #3511. 2015-07-30 08:57:52 +03:00
Chocobo1
a8f0acecb7 Migrate TravisCI to container-based infrastructure, closes #3506. 2015-07-30 12:02:00 +08:00
sledgehammer999
8f1f57afe4 Remove obsolete Boost configurations. 2015-07-30 01:51:55 +03:00
sledgehammer999
0209a9f41d Merge pull request #3228 from Chocobo1/win_build
Compilation on windows
2015-07-30 00:21:11 +03:00
sledgehammer999
bf3a6d1c20 Merge pull request #3455 from Chocobo1/label_fix
Fix '&' character in label name becomes accelerator key, closes #3454.
2015-07-29 23:30:25 +03:00
sledgehammer999
256793aad7 Merge pull request #3447 from glassez/filters
Fix label filter. Closes #3429.
2015-07-29 23:28:47 +03:00
sledgehammer999
a56c21551d Merge pull request #3458 from Chocobo1/path_fix
Use `rootPath()` in save path field
2015-07-29 23:24:51 +03:00
sledgehammer999
fce3a2d5c0 Merge pull request #3457 from Chocobo1/ext_param
Add more "Run External Program" parameters
2015-07-29 23:17:19 +03:00
sledgehammer999
675298bc73 Merge pull request #3483 from glassez/bandwidth
Fix Bandwidth Scheduler. Closes #3376.
2015-07-29 22:28:22 +03:00
sledgehammer999
6985b553af Merge pull request #3494 from glassez/drop_libtorrent_0
Drop libtorrent 0.16.x support.
2015-07-29 22:15:45 +03:00
Gabriele
885eb64df3 Follow project coding style. Issue #2192. 2015-07-29 19:58:22 +02:00
Chocobo1
2ce9aa20a5 Fix "Run External Program Launches too Early" issue, closes #2107. 2015-07-28 18:21:56 +08:00
Chocobo1
be34f29b05 Fix warnings by qmake -Wall, cleanups 2015-07-28 16:55:01 +08:00
Chocobo1
077e94342f Add path to openssl, cleanups 2015-07-28 16:55:01 +08:00
Chocobo1
09d7d9a360 Update .gitignore 2015-07-28 16:55:01 +08:00
sledgehammer999
438ee23d2c Bump version status. 2015-07-28 03:07:42 +03:00
sledgehammer999
4f2d74f793 Merge pull request #3374 from ngosang/webui_info
[Web UI] Add information in General tab
2015-07-28 03:03:45 +03:00
sledgehammer999
0e62a52e59 Merge pull request #3493 from ngosang/python
Improve Python detection
2015-07-28 02:59:25 +03:00
sledgehammer999
369561f8f7 Fix typo in string which prevents word substitution. 2015-07-28 02:05:29 +03:00
ngosang
69812bbf18 Converts the string "Seeded for" to lowercase 2015-07-26 14:33:11 +02:00
ngosang
e33570625f [Web UI] Fix friendlyUnit() implementation. Related to #2719 2015-07-26 14:31:11 +02:00
ngosang
2132704e1d [Web UI] Add information in General tab 2015-07-26 14:27:59 +02:00
ngosang
38a6f4cc34 Improve Python detection 2015-07-26 14:15:40 +02:00
sledgehammer999
626a3b10d3 [webui] Fix ugly 'C++' wrapping in About dialog. 2015-07-26 00:35:04 +03:00
sledgehammer999
c7fa778732 Merge pull request #2702 from pmzqla/rss-count
Add count of unread items to RSS tab label
2015-07-26 00:29:47 +03:00
Vladimir Golovnev (Glassez)
e72cc4eaf9 Drop libtorrent 0.16.x support. 2015-07-25 19:00:18 +03:00
Gabriele
c48407e038 Add count of unread items to RSS tab label
Closes #2681.
2015-07-25 11:57:03 +02:00
sledgehammer999
7c7bb14a93 Sync translations from Transifex and run lupdate. 2015-07-25 03:24:44 +03:00
sledgehammer999
f9dc76928c Merge pull request #3467 from ngosang/webui_refresh
[Web UI] Massive increase in performance.
2015-07-23 01:17:57 +03:00
sledgehammer999
5b7ea0e611 Merge pull request #3186 from glassez/geoip
New GeoIP manager.
2015-07-22 23:59:00 +03:00
sledgehammer999
5437674fdf Fix installing search plugin by drag-n-dropping file. 2015-07-22 23:29:57 +03:00
sledgehammer999
21f18d015d Fix installing search plugin from local file. 2015-07-22 23:29:50 +03:00
sledgehammer999
47d9c12f4b Fix segfault on Linux due to early initialization of global var.
Utils::Misc::pythonVersion() gets called before the Logger is initialized.
2015-07-22 23:29:43 +03:00
sledgehammer999
f6bbd9377f Improve checks for python. Print python version and path to log. 2015-07-22 23:29:35 +03:00
Chocobo1
3baec1c327 Add more "Run External Program" parameters, closes #3053, #238, #1291, #1522. 2015-07-22 15:25:31 +08:00
Chocobo1
bd657fe9ae Move option "Ignore transfer limits on local network" to Speed page 2015-07-22 14:52:24 +08:00
Vladimir Golovnev (Glassez)
64ebc5cfd6 Fix Bandwidth Scheduler. Closes #3376. 2015-07-22 08:54:23 +03:00
Vladimir Golovnev (Glassez)
84922dcdcf Fix need restart to enable/disable peer countries resolution. 2015-07-22 08:07:13 +03:00
Vladimir Golovnev (Glassez)
79976fbfce Implement new GeoIPManager class. 2015-07-22 08:06:51 +03:00
Vladimir Golovnev (Glassez)
c702a7e426 Improve DownloadManager.
Now we can use downloaded data directly without saving to file.
We also can disable redirection to Magnet URI handling (useful for
non-torrent files downloading).
2015-07-21 09:50:39 +03:00
Vladimir Golovnev (Glassez)
336519b7b5 Move compression functions to Utils::Gzip. 2015-07-21 09:37:32 +03:00
sledgehammer999
dfb2f8b3b3 Merge pull request #3469 from ngosang/search_py32
[search engine] Fix cpu_count in old Python versions
2015-07-21 01:58:01 +03:00
sledgehammer999
8b99e29dc0 Fixup previous commits on python search. 2015-07-21 01:56:14 +03:00
sledgehammer999
d6af4683bb Merge pull request #2624 from pmzqla/python
Prefer python3 over python2
2015-07-21 01:55:14 +03:00
ngosang
32c813eece [search engine] Fix cpu_count in old Python versions 2015-07-20 19:12:58 +02:00
ngosang
03f86a71de Change Queue buttons order in the Toolbar (GUI & Web UI) 2015-07-20 04:44:29 +02:00
ngosang
2db942e606 [Web UI] Massive increase in performance. 2015-07-20 02:13:44 +02:00
sledgehammer999
6668018b45 Static order of items in the transferlist menu. 2015-07-20 02:48:11 +03:00
sledgehammer999
f21cafb605 Merge pull request #3410 from ngosang/preview
Minor changes in the GUI (Preview file & Forece Resume)
2015-07-20 02:46:40 +03:00
sledgehammer999
3864a7fdc6 Fix compiler warning for unused variable. 2015-07-20 00:13:18 +03:00
Chocobo1
ff8f37b262 Save trimmed string in preference 2015-07-20 01:16:15 +08:00
sledgehammer999
783f17ec4d Merge pull request #3456 from Chocobo1/localhost
Fix translated localhost address (::ffff:127.0.0.1) is not recognized
2015-07-19 19:37:59 +03:00
sledgehammer999
46a0eb4aa4 Update Changelog. 2015-07-19 19:34:54 +03:00
sledgehammer999
2de5390c08 Merge pull request #3433 from ngosang/webui_extlinks
[Web UI] Open external links in a new window/tab
2015-07-19 18:57:59 +03:00
sledgehammer999
bfaa0789f0 Merge pull request #3428 from ngosang/webui_queuenum
[Web UI] Fix sort by queue number
2015-07-19 18:52:18 +03:00
sledgehammer999
eb73e7c1d4 Merge pull request #3150 from ngosang/add_peer_dialog
Add multiple peers in Peers addition dialog. Closes #1563, #2245, #3133, #1419, #3287, #1419
2015-07-19 18:33:10 +03:00
ngosang
63ed69789b Allow to copy all peers with a keyboard shortcut 2015-07-19 13:04:30 +02:00
sledgehammer999
983c19eb29 Merge pull request #2676 from pmzqla/copytrackers
Allow to copy all the trackers with a keyboard shortcut
2015-07-19 14:04:28 +03:00
ngosang
cef3c9a34d Add multiple peers in Peers addition dialog. Closes #1563, #2245, #3133, #1419, #3287, #1419 2015-07-19 13:04:00 +02:00
Chocobo1
030dd9eed8 Use rootPath() in save path field 2015-07-19 18:17:28 +08:00
Chocobo1
6721363f8c Resave in Qt designer 2015-07-19 16:04:25 +08:00
Chocobo1
8bb2e98b90 Fix localhost address (::ffff:127.0.0.1) is not recognized when connecting to WebUI 2015-07-19 14:48:58 +08:00
Chocobo1
58b600198f Fix '&' character in label name becomes accelerator key, closes #3454. 2015-07-19 13:41:44 +08:00
sledgehammer999
5281593bb6 Fix qt5 compilation with QtConcurrent. 2015-07-18 21:06:50 +03:00
sledgehammer999
0b20794672 Fixup speedwidget code. 2015-07-18 19:31:51 +03:00
sledgehammer999
8dd7014af6 Merge pull request #2757 from onto/master
Upload/download speed graph widget.
2015-07-18 19:30:29 +03:00
Anton Lashkov
7b736b6ae3 Add speedwidget based on QGraphicsView 2015-07-18 00:54:36 +04:00
Vladimir Golovnev (Glassez)
d475ab3881 Fix label filter. Closes #3429. 2015-07-16 14:39:25 +03:00
sledgehammer999
b26724d12b Merge pull request #3437 from ngosang/extratorrent
[search engine] Remove the word 'torrent' in ExtraTorrent results
2015-07-16 00:47:23 +03:00
sledgehammer999
3d71ea5bc0 Merge pull request #3431 from Chocobo1/announce
DHT announce
2015-07-16 00:16:44 +03:00
ngosang
1f4d01e512 [Web UI] Changes in Force Resume icon and menu order 2015-07-15 23:12:12 +02:00
ngosang
9dbb2720b0 Changes in Force Resume icon and menu order 2015-07-15 22:46:24 +02:00
ngosang
808f07250e Minor changes in Preview File dialog 2015-07-15 22:46:24 +02:00
sledgehammer999
ed45ff89f8 Merge pull request #2861 from DoumanAsh/search_status_tab
Search status tab
2015-07-15 23:07:59 +03:00
sledgehammer999
d59440f99e Fix printing of the copyright symbol in the About dialog. 2015-07-15 22:45:13 +03:00
sledgehammer999
b80ced2b3a Don't add a torrent which doesn't have a matching .torrent file to its .fastresume file. Closes #3346. 2015-07-15 21:01:07 +03:00
Chocobo1
8873900df3 Also reannounce to DHT when "Force reannounce to all trackers" is selected 2015-07-15 07:05:04 +08:00
Chocobo1
4d6bde9731 Remove announce to DHT after editing tracker list 2015-07-15 07:05:04 +08:00
Chocobo1
fb1772f019 Rewrite TrackerList::reannounceSelected(), now it can force reannounce DHT 2015-07-15 07:05:04 +08:00
ngosang
cc503b36e8 [search engine] Remove the word 'torrent' in ExtraTorrent results 2015-07-15 00:27:09 +02:00
ngosang
0fe99fe10f [Web UI] Open external links in a new window/tab 2015-07-14 12:16:01 +02:00
DoumanAsh
e2aa8056af Search status uses tab's status 2015-07-14 09:03:27 +03:00
ngosang
10bba1a632 [Web UI] Fix sort by queue number 2015-07-14 01:48:05 +02:00
sledgehammer999
5e400d3117 Merge pull request #3377 from BlaXpirit/recheck-confirmation-setting
Implement an option to disable confirmation of torrent recheck
2015-07-14 00:32:53 +03:00
sledgehammer999
39e0c560cf Update color scheme of completed.png icon. 2015-07-13 23:44:55 +03:00
sledgehammer999
bf13238ccf Merge pull request #3385 from ngosang/webui_addtracker
[Web UI] Fix empty trackers addition
2015-07-13 23:37:14 +03:00
sledgehammer999
5b56717501 Merge pull request #3394 from ngosang/json3
[Web UI] Fix API Content Types. Closes #3393
2015-07-13 23:36:34 +03:00
sledgehammer999
de84bb9824 Merge pull request #3407 from glassez/seqdl
Fix restore sequential download state.
2015-07-13 23:35:17 +03:00
DoumanAsh
496f843016 Replace indent to 4 spaces 2015-07-13 09:31:23 +03:00
sledgehammer999
c1e2ddc843 Merge pull request #3384 from ngosang/webui_upnp
[Web UI] New option Web UI port UPNP. Closes #3358
2015-07-13 00:46:58 +03:00
ngosang
ac74f14408 Increase API_VERSION 2015-07-12 23:08:43 +02:00
ngosang
3a44b94cc7 [Web UI] New option Web UI port UPNP. Closes #3358 2015-07-12 23:07:49 +02:00
sledgehammer999
948b2c0410 Merge pull request #3375 from ngosang/completed_filter
Add Force Seeding state to Completed filter
2015-07-12 15:44:01 +03:00
sledgehammer999
d4151c1832 Merge pull request #3395 from ngosang/content_percent
Fix progress calculation in Content tab. Closes #2639 Closes #2752
2015-07-12 15:42:46 +03:00
sledgehammer999
365d039209 Merge pull request #3386 from ngosang/webuibug
[Web UI] Fix an error in Content tab when the torrent doesn't have me…
2015-07-12 14:39:13 +03:00
sledgehammer999
40c9727cb9 Merge pull request #3383 from ngosang/webui_port
[Web UI] Ports between 1 and 65535 as in the GUI. Closes #1602
2015-07-12 14:33:39 +03:00
sledgehammer999
e6946042ae Merge pull request #3382 from ngosang/webui_trackmenu
[Web UI] Torrent download from hash. Closes #1173
2015-07-12 14:27:40 +03:00
Vladimir Golovnev (Glassez)
8e03f01518 Fix restore sequential download state. 2015-07-12 13:56:24 +03:00
ngosang
6413537f45 [Web UI] Fix API Content Types. Closes #3393 2015-07-12 01:29:03 +02:00
ngosang
e20a24ab2e Fix progress calculation in Content tab. Closes #2639 Closes #2752 2015-07-12 01:27:16 +02:00
ngosang
47c31c8b03 [Web UI] Ports between 1 and 65535 as in the GUI. Closes #1602 2015-07-12 01:24:34 +02:00
ngosang
f0d32e2cde [Web UI] Torrent download from hash. Closes #1173 2015-07-12 01:21:09 +02:00
ngosang
62b803e268 [Web UI] Fix empty trackers addition 2015-07-11 15:35:53 +02:00
ngosang
9ea56ea5d4 [Web UI] Fix an error in Content tab when the torrent doesn't have metadata 2015-07-09 18:11:04 +02:00
Oleh Prypin
7474c05209 Implement an option to disable confirmation of torrent recheck 2015-07-08 23:29:31 +03:00
sledgehammer999
647140c7c7 Merge pull request #3371 from ngosang/webuialterdl
[Web UI] Fix alternative global rate limits. Closes #3359
2015-07-08 21:19:08 +03:00
sledgehammer999
46c54e51ee Update Changelog. 2015-07-08 19:19:11 +03:00
sledgehammer999
9eee92b5c6 Merge pull request #3372 from ngosang/torrentz_speed
[search engine] Fix Python 2 implementation of Torrentz
2015-07-08 18:25:57 +03:00
ngosang
ac2c8a3d30 Add Force Seeding state to Completed filter 2015-07-08 16:01:10 +02:00
ngosang
ee44fd54b6 [search engine] Fix Python 2 implementation of Torrentz 2015-07-08 11:04:50 +02:00
ngosang
0ed8ea9599 [Web UI] Additional checks in Options dialog 2015-07-08 09:53:01 +02:00
ngosang
d9ef7c1b32 [Web UI] Reorder Options dialog code 2015-07-08 09:06:41 +02:00
ngosang
357334fb46 [Web UI] Fix alternative global rate limits. 2015-07-08 06:47:59 +02:00
sledgehammer999
d0b54b0797 Merge pull request #3348 from ngosang/webuistates
[Web UI] Fix missing torrent states.
2015-07-04 02:24:32 +03:00
ngosang
768e87b0da [Web UI] Fix missing torrent states. 2015-07-04 01:04:10 +02:00
sledgehammer999
14187978c0 Update Chinese locale names for WebUI too. 2015-07-03 22:52:08 +03:00
sledgehammer999
cac91737ac Sync translations from Transifex and run lupdate. 2015-07-03 22:34:36 +03:00
sledgehammer999
0b18e7bd60 Add unicodestrings.h to core.pri 2015-07-03 22:22:14 +03:00
sledgehammer999
61705fdd42 Partially revert fb7ba92f6 and split the Chinese locales into 3.
Chinese Simplified, Chinese Traditional(Taiwan), Chinese Traditional(Hong Kong).
Closes #3262.
2015-07-03 22:20:32 +03:00
sledgehammer999
6dd3795b7a Fix Properties bar size when started minimized to tray. Closes #3206. 2015-07-03 22:09:37 +03:00
sledgehammer999
2e0c3f8751 Merge pull request #3329 from glassez/state
Fix missing torrent states. Closes #3302.
2015-07-03 21:58:57 +03:00
sledgehammer999
e1e8471728 Merge pull request #3324 from pmzqla/sort-eta-master
Fix sorting torrents by ETA
2015-07-03 21:55:52 +03:00
Heiko Becker
3c66997427 Add missing QDataStream include
Fixes building with Qt 5.5.0-beta.
2015-06-30 22:04:34 +03:00
Vladimir Golovnev (Glassez)
5ec2af7b5a Fix missing torrent states. 2015-06-30 11:14:41 +03:00
Gabriele
d3b23e4b81 Fix sorting torrents by ETA
Same as #2966.
Related issue: #2965.
2015-06-29 21:03:44 +02:00
Gabriele
d76a84048b Increase priority value of "High"
It was observed that setting the priority of a file to High has almost
no effect, so increase its value.
2015-06-29 02:01:51 +03:00
Gabriele
f21fbff1a8 Use enums instead of values when dealing with file priorities
Manually backported commit 10880e10f1 from v3_2_x branch.
2015-06-29 02:00:50 +03:00
sledgehammer999
c17a56cb8b Merge pull request #3318 from ngosang/searchorder
Fix column sort in search engine. Closes #2621
2015-06-29 01:42:17 +03:00
ngosang
b23608ec35 Fix column sort in search engine. Closes #2621 2015-06-28 23:51:09 +02:00
sledgehammer999
a8df699441 Merge pull request #3197 from ngosang/webui_websources
[Web UI] Add Web Seeds (HTTP Sources) tab
2015-06-28 19:34:23 +03:00
sledgehammer999
1b430abb16 Don't use a default upload limit. Closes #3275. 2015-06-28 19:21:47 +03:00
sledgehammer999
e4062e0f35 Sync translations from Transifex and run lupdate. 2015-06-28 18:18:44 +03:00
ngosang
e6f2926ccd [Web UI] Don't update the tabs if tab's panel is collapsed 2015-06-28 16:36:46 +02:00
ngosang
263d45ca9d [Web UI] Use camelCase in variable names 2015-06-28 16:36:46 +02:00
ngosang
8e4b9f30bb [Web UI] Add Web Seeds (HTTP Sources) tab 2015-06-28 16:36:45 +02:00
sledgehammer999
f12b300298 Partially revert e675625d0d.
It causes problems with Travis CI builds because travis checks out the branch which might have newer commits and not find our particular commit.
2015-06-28 16:43:04 +03:00
sledgehammer999
2db4a661ee Merge pull request #3251 from Chocobo1/unicode_fix
Fix MSVC2013 complains on Unicode characters
2015-06-28 16:12:47 +03:00
sledgehammer999
3c6ee3d57f Merge pull request #3317 from ngosang/search_eng
Cosmetics changes in search engine
2015-06-28 16:11:20 +03:00
Chocobo1
e2a1211513 Mention github contributors in thanks.html 2015-06-28 21:08:21 +08:00
Chocobo1
436b3a472a Move translators & thanks to its own file
Add HTML header & cleanup
2015-06-28 21:08:20 +08:00
sledgehammer999
f177ecd50c Merge pull request #3313 from Chocobo1/travis
Travis script update
2015-06-28 16:07:51 +03:00
Chocobo1
e675625d0d Switch to libtorrent git repository
Reduce clone depth to 1
Fix missing variable when compiling for coverity scan
2015-06-28 21:02:41 +08:00
ngosang
326a74425f Cosmetics changes in search engine 2015-06-28 14:38:17 +02:00
sledgehammer999
a217d97fda Merge pull request #3304 from Chocobo1/menu_cap
Capitalize menu item
2015-06-28 15:17:37 +03:00
sledgehammer999
6959084f98 Merge pull request #3315 from Chocobo1/disk_space
Update disk space label after changing partition, closes #3309.
2015-06-28 15:16:29 +03:00
sledgehammer999
216bf9b477 Merge pull request #3279 from ngosang/webui_newoptions
[Web UI] Add new options
2015-06-28 15:15:35 +03:00
Chocobo1
3efb311076 Better message for users 2015-06-28 19:37:31 +08:00
ngosang
3ac9b2525e Increase API_VERSION due to changes in #3279, #3197, #3226 and #3040 2015-06-28 13:33:56 +02:00
ngosang
831b47b8f9 [Web UI] Add new options 2015-06-28 13:33:51 +02:00
ngosang
ff10eafcbc Follow project coding style. Issue #2192. 2015-06-28 13:32:57 +02:00
Chocobo1
38c0dbfc95 Update disk space label after changing partition, closes #3309. 2015-06-28 19:32:54 +08:00
Chocobo1
e739e81205 Fix compilation on MSVC2013 by moving unicode strings to
"unicodestrings.h". Closes #3059.
2015-06-28 19:18:57 +08:00
sledgehammer999
1bcfae5265 Merge pull request #3308 from ngosang/torrentreactorimp
[search engine] Update TorrentReactor
2015-06-28 14:13:25 +03:00
ngosang
b249b461d7 [search engine] Update TorrentReactor 2015-06-28 12:54:34 +02:00
sledgehammer999
af79ba433c Merge pull request #3307 from ngosang/extratorrentimp
[search engine] Update ExtraTorrent
2015-06-28 13:46:08 +03:00
sledgehammer999
14013c80c0 Merge pull request #3270 from Chocobo1/info_box
Reorder layout in information box
2015-06-28 13:45:25 +03:00
ngosang
85a7c7303d [search engine] Update ExtraTorrent 2015-06-28 12:36:33 +02:00
sledgehammer999
f94214ae14 Merge pull request #3291 from ngosang/torrent_creator
Add 16 KiB, 8 MiB and 16 MiB piece sizes in Torrent Creator. Closes #2656
2015-06-28 13:31:06 +03:00
sledgehammer999
ca4fbe40dd Merge pull request #3306 from ngosang/torrentzimp
[search engine] Update Torrentz
2015-06-28 13:30:31 +03:00
ngosang
91818417be Add 16 KiB, 8 MiB and 16 MiB piece sizes in Torrent Creator 2015-06-28 12:26:24 +02:00
ngosang
577ace4971 Follow project coding style. Issue #2192. 2015-06-28 12:26:03 +02:00
Chocobo1
776d91f663 Add connectionsLimit() back 2015-06-28 18:15:17 +08:00
sledgehammer999
b9ed94a098 Merge pull request #3292 from glassez/resumedata
Fix save resume data for torrents w/o metadata. Closes  #1488.
2015-06-28 12:43:00 +03:00
sledgehammer999
800630a813 Merge pull request #3290 from glassez/trackers
Fix trackers removing (#2892 regression).
2015-06-28 12:42:34 +03:00
sledgehammer999
4854a1b2ee Merge pull request #3311 from ngosang/btdiggimp
[search engine] Update BTDigg
2015-06-28 12:32:47 +03:00
sledgehammer999
bcfb8f1f53 Merge pull request #3312 from ngosang/kickassimp
[search engine] Update KickassTorrents
2015-06-28 12:30:30 +03:00
ngosang
2afa282190 [search engine] Update BTDigg 2015-06-27 21:33:50 +02:00
ngosang
2b2ffca7d0 [search engine] Update Torrentz 2015-06-27 21:00:47 +02:00
ngosang
650e7018a7 [search engine] Update KickassTorrents 2015-06-27 18:25:20 +02:00
Chocobo1
1e0ac5c5f1 Capitalize menu item, missed in b4a855f. 2015-06-26 14:16:57 +08:00
Vladimir Golovnev (Glassez)
b9c087f46c Fix save resume data for torrents w/o metadata. 2015-06-24 18:49:55 +03:00
Chocobo1
9d5cfbcda9 Preserve plain text formatting 2015-06-24 19:28:31 +08:00
Vladimir Golovnev (Glassez)
ffe6292237 Fix trackers removing. 2015-06-24 14:09:43 +03:00
sledgehammer999
9d97c05889 Merge pull request #3282 from ngosang/search_check
[search engine] Fix novaprinter.py version number
2015-06-23 18:22:13 +03:00
sledgehammer999
2658b39434 Merge pull request #3283 from glassez/rss
Fix add torrent dialog is not shown (#2892 regression).
2015-06-23 18:21:24 +03:00
sledgehammer999
f6cf07a147 Merge pull request #3284 from glassez/about
Fix ugly 'C++' wrapping in About dialog.
2015-06-23 18:21:13 +03:00
Vladimir Golovnev (Glassez)
4752fa5301 Fix ugly 'C++' wrapping in About dialog. 2015-06-23 13:22:52 +03:00
Vladimir Golovnev (Glassez)
f40d3d1fc6 Fix add torrent dialog is not shown. 2015-06-23 11:19:34 +03:00
ngosang
d7ffabe7ca [search engine] Fix novaprinter.py version number 2015-06-23 09:46:19 +02:00
Chocobo1
b318f54fdf Force set "plain text" format to reduce attack vector. 2015-06-22 22:10:33 +08:00
Chocobo1
661ddd75b6 Allow wordWrap for "Save Path" & "Comment" 2015-06-22 13:32:32 +08:00
sledgehammer999
bc97208516 Merge pull request #3187 from glassez/model
Improve TorrentModel class (Issue #2433).
2015-06-21 16:32:30 +03:00
Vladimir Golovnev (Glassez)
64c8f61bb1 Improve TorrentModel class. 2015-06-21 16:28:21 +03:00
sledgehammer999
7699b7ce6f Merge pull request #3271 from glassez/rename
Fix torrent renaming (3715e8d2 regression).
2015-06-21 16:00:49 +03:00
Vladimir Golovnev (Glassez)
347832d852 Fix torrent renaming (3715e8d2 regression). 2015-06-21 13:32:48 +03:00
Chocobo1
50b3a24371 Change Comment field from QTextBrowser to QLabel 2015-06-21 13:52:11 +08:00
Chocobo1
4d5512dcca Reorder layout in information box 2015-06-21 13:20:19 +08:00
sledgehammer999
2e6c890883 Partially revert 30f21259f8.
Fixes Linux issue for when the theme doesn't have a corresponding icon.
2015-06-21 00:56:18 +03:00
sledgehammer999
f94d733c62 Minimize to tray only if the relevant option is enabled. 2015-06-20 23:28:40 +03:00
sledgehammer999
9032808112 Fix sorting by queue. 2015-06-20 20:05:49 +03:00
sledgehammer999
a22137e06e Merge pull request #3240 from ngosang/webui_interface
[Web UI] Changes in menus, new features and reordered Options.
2015-06-20 19:31:06 +03:00
ngosang
973518694e [Web UI] Tabs indentation replaced with spaces 2015-06-20 18:18:36 +02:00
ngosang
d6caf1c839 [Web UI] Reorder the tabs/groups in Options window 2015-06-20 18:04:23 +02:00
ngosang
6f7dca1f83 [Web UI] Option to hide Top Toolbar 2015-06-20 18:04:18 +02:00
sledgehammer999
dbbf1a8fce Merge pull request #2690 from Chocobo1/dev4
Don't close downloadFromURL dialog when showing empty url warning.
2015-06-20 18:50:51 +03:00
sledgehammer999
27e18f0eb8 Merge pull request #2643 from mayankasthana/tab_FocusChange
Download-from-URL textbox change focus on tab key
2015-06-20 18:43:37 +03:00
ngosang
bbc667cb78 [Web UI] Changes in menus to keep the client's style 2015-06-20 17:36:13 +02:00
sledgehammer999
74d757f0f1 Delete tempfile when downloading favicon.ico. Closes #3257. 2015-06-20 18:21:20 +03:00
sledgehammer999
a224650281 Merge pull request #3078 from Chocobo1/props_widget
Revamp general tab info, closes #982
2015-06-20 16:50:32 +03:00
sledgehammer999
54abcfcd93 Merge pull request #3260 from glassez/sort
Fix torrent state sort order (#2892 regression).
2015-06-20 16:40:47 +03:00
sledgehammer999
627d74233b Merge pull request #3245 from glassez/upgrade
Upgrade to v3.3
2015-06-20 16:33:32 +03:00
Vladimir Golovnev (Glassez)
b29f6916cb Implement upgrage code. 2015-06-20 16:23:10 +03:00
Vladimir Golovnev (Glassez)
7041a96fda Fix torrent state sort order. 2015-06-20 16:03:56 +03:00
Chocobo1
6bc42cfd1a Add functionality to new data fields, cleanups 2015-06-20 20:42:44 +08:00
Chocobo1
bd8b8a8c8f Use warning message box instead of critical 2015-06-20 20:36:35 +08:00
sledgehammer999
cf1a62cec3 Merge pull request #2719 from Chocobo1/dev6
Fix potential out-of-bound access in misc::friendlyUnit()
2015-06-20 02:46:47 +03:00
sledgehammer999
fd6fcffa67 Merge pull request #3247 from glassez/ratio
Fix ratio limit for new torrents. Closes #3210.
2015-06-19 18:53:40 +03:00
sledgehammer999
75fecf9645 Merge pull request #3226 from ngosang/webui_dhtport
[Web UI] Remove DHT port setting. Closes #3225
2015-06-18 23:37:53 +03:00
Vladimir Golovnev (Glassez)
04f3f9d29d Fix ratio limit for new torrents. 2015-06-18 16:28:52 +03:00
sledgehammer999
fb7ba92f69 Rename Chinese translation files. Closes #2936. 2015-06-17 23:06:08 +03:00
sledgehammer999
c259666e43 Merge pull request #2803 from Chocobo1/shutdown
WebUI: add delay in shutdown command in order to send out response msg
2015-06-17 22:58:49 +03:00
Gabriele
6609d3e89f Don't use list of versions for the Python fallback detection on Windows
Always pick the newest versions among those installed.
2015-06-17 21:30:35 +02:00
Gabriele
f4c44ce128 Don't specify the Python version required in the notification
Both python2 and python3 are supported.
2015-06-17 21:30:35 +02:00
Gabriele
a8276dd70f Update link to the Windows Python installer
From v2.7.3 to v3.4.3.
2015-06-17 21:30:35 +02:00
Gabriele
0c23d22472 Show notification if Python is not found and a search is started
Also, don't bother starting a search if it's known that Python is
not available.
2015-06-17 21:30:12 +02:00
Gabriele
e34cc79dad Use python3 and python2 instead of python on Linux
Prefer python3 over python2 when both are available.

Both python2 and python3 should always exists.
More info at: http://legacy.python.org/dev/peps/pep-0394/
2015-06-17 21:29:20 +02:00
Vladimir Golovnev (Glassez)
de712c6ba9 Use native QDir::removeRecursively() in Qt5. 2015-06-17 19:19:56 +03:00
sledgehammer999
1396c63525 Merge pull request #3224 from glassez/fastresume
Fix resume torrents without metadata.
2015-06-17 19:12:22 +03:00
Vladimir Golovnev (Glassez)
8cc9c64ff8 Fix resume torrents without metadata. 2015-06-17 19:06:48 +03:00
Chocobo1
64665146e1 Expose more data fields 2015-06-17 23:20:34 +08:00
Chocobo1
cdec6c9027 Add new data fields, capitialize labels, cleanups 2015-06-17 23:20:34 +08:00
sledgehammer999
0172ab1f50 Merge pull request #3242 from glassez/hotfixes
Fix some #2892 regressions. Closes #3210.
2015-06-17 17:45:14 +03:00
Vladimir Golovnev (Glassez)
d76c4554e2 Fix MaxRatio ignoring. 2015-06-17 14:45:47 +03:00
Vladimir Golovnev (Glassez)
3d09f579d0 Fix torrent creation date loss. 2015-06-17 11:21:41 +03:00
Chocobo1
e95a017e33 Fix potential out-of-bound access of units[i] 2015-06-17 08:03:51 +08:00
sledgehammer999
2c91157926 Update settings for Coverity Scan. 2015-06-17 00:19:00 +03:00
sledgehammer999
d2697cd124 Merge pull request #2957 from Chocobo1/coverity_scan
Hookup to Coverity Scan, Closes #2601
2015-06-17 00:13:51 +03:00
sledgehammer999
061fbeff56 Merge pull request #3234 from glassez/openfile
Fix crash when cancel open file dialog.
2015-06-16 22:55:57 +03:00
Vladimir Golovnev (Glassez)
77b3a0c4cd Fix crash when cancel open file dialog.
Closes #3232.
2015-06-16 09:09:08 +03:00
ngosang
8340abbe63 [Web UI] Remove DHT port setting. Closes #3225 2015-06-15 11:00:36 +02:00
sledgehammer999
3f8e76ce93 Clear missing files flag when resuming or force rechecking. Fixes issues in #2750. 2015-06-15 00:48:28 +03:00
sledgehammer999
a2c48646ae New translation: Indonesian. 2015-06-14 23:43:21 +03:00
sledgehammer999
78f5b960a0 Sync translations from Transifex and run lupdate. 2015-06-14 23:28:28 +03:00
sledgehammer999
f6236d13d1 Merge pull request #3190 from Chocobo1/ratio_fix_master
Improve ratio calculation formula
2015-06-14 23:02:34 +03:00
sledgehammer999
6b56a8accf Merge pull request #3211 from yurivict/compile-issues
Added missing include <cstdlib>
2015-06-14 21:50:13 +03:00
sledgehammer999
9febd608c6 Merge pull request #3216 from Chocobo1/rm
Fix additional file included in #3167
2015-06-14 21:49:21 +03:00
sledgehammer999
e4282c10c7 Merge pull request #2847 from Chocobo1/move_stats
Revamp menu items
2015-06-14 20:21:27 +03:00
sledgehammer999
575578428c Merge pull request #3167 from Chocobo1/opt_ip_filter_tracker
Add checkbox option for IpFilterTrackers, closes #3154.
2015-06-14 20:15:12 +03:00
Chocobo1
6e1bfdef4c Fix additional file included in 32a712f 2015-06-15 00:02:07 +08:00
Chocobo1
36da49667a Resave in Qt Designer 2015-06-14 20:01:14 +08:00
Chocobo1
ade1936f9c Remove menu items: "Visit Website" and "Report a Bug".
Many issues opened on github should be asked on forum first, and the links are already present in "About" window.
2015-06-14 20:01:14 +08:00
Chocobo1
580642b08e Rename "Execution Log" to "Log".
Rename "When Downloads Done" to "On Downloads Done".
2015-06-14 20:01:14 +08:00
Chocobo1
b4a855f4c1 Move statistics from Tools to View
Reorder & add separators in Help menu

Rename `Auto-Shutdown on downloads completion` to `When downloads done`

Capitalize menu items, modify accelerator
2015-06-14 20:01:11 +08:00
Chocobo1
32a712f005 Add checkbox option for IpFilterTrackers, closes #3154. 2015-06-14 19:10:11 +08:00
Yuri
ea2b2937b9 Added missing include <cstdlib> for rand(3) 2015-06-14 03:17:12 -07:00
Yuri
a86961a22e Added missing include <cstdlib> for rand(3) 2015-06-14 03:14:27 -07:00
Chocobo1
2299580dc9 Improve ratio calculation formula. Closes #3096. 2015-06-14 17:45:40 +08:00
sledgehammer999
77786bb8bb Add translator to credits. 2015-06-14 12:28:08 +03:00
sledgehammer999
9ee67364c2 Merge pull request #3209 from ngosang/minor_fixes
Code clean up
2015-06-14 11:40:41 +03:00
ngosang
4a76526417 Code clean up
This changes were proposed by @PiotrNawrot in these PRs: #2967, #2970.
2015-06-14 10:35:32 +02:00
sledgehammer999
f89c44e1a0 Merge pull request #2938 from dartraiden/master
Fixed typos, spelling correction
2015-06-14 11:20:15 +03:00
dartraiden
8ac83cfd42 Fixed typos, spelling correction 2015-06-14 10:55:46 +03:00
sledgehammer999
f5b0008158 Merge pull request #2805 from ngosang/typo_revision
Changes in typography
2015-06-13 22:06:12 +03:00
sledgehammer999
1be26cf2bd Merge pull request #2808 from ngosang/AnnounceToAllTrackers
Change default preferences
2015-06-13 21:39:45 +03:00
ngosang
e01a61d816 changes in typography 2015-06-13 20:04:20 +02:00
sledgehammer999
25e04ee2f3 Merge pull request #3191 from Chocobo1/neg_loop_master
Fix potential negative loop bound
2015-06-13 21:03:41 +03:00
sledgehammer999
4d848e99f0 Merge pull request #3004 from ngosang/cppcheck_fixes
Cppcheck: scope reduction & unused variables
2015-06-13 20:16:53 +03:00
sledgehammer999
157b1eadfa Merge pull request #3203 from glassez/unistd
Fix qbittorrent-nox compilation.
2015-06-13 09:33:44 +03:00
Vladimir Golovnev (Glassez)
5798fb959d Fix qbittorrent-nox compilation. 2015-06-13 09:20:16 +03:00
sledgehammer999
35e04a795d Merge pull request #3194 from glassez/save_path
Fix BitTorrent::TorrentHandle class.
2015-06-13 01:51:27 +03:00
sledgehammer999
e22f7570fe Merge pull request #3192 from who-me/patch-1
Update qBittorrent.appdata.xml (invalid tag)
2015-06-13 01:47:58 +03:00
sledgehammer999
93bbda851a Merge pull request #3188 from glassez/datetime
Fix time_t 0 special meaning.
2015-06-13 01:46:12 +03:00
sledgehammer999
2c34aa4ea2 Merge pull request #3179 from DoumanAsh/legittorrents_update
[search engine] Update Legit Torrent to remove sgmllib
2015-06-13 01:44:28 +03:00
sledgehammer999
4f5ce16dcb Merge pull request #3176 from DoumanAsh/py3_remove_cache
[search engine] Remove python3 cache during updateNova()
2015-06-13 01:38:58 +03:00
sledgehammer999
df2068d734 Merge pull request #3010 from ngosang/user-agent
Changes in User-Agents
2015-06-13 01:37:21 +03:00
DoumanAsh
033817f70b [search engine] Update Legit Torrent to remove sgmllib 2015-06-12 18:23:56 +03:00
Vladimir Golovnev (Glassez)
9c28977001 Fix adjustActualSavePath() when torrent is moving. 2015-06-12 15:37:52 +03:00
Vladimir Golovnev (Glassez)
a55a27508a Fix append .!qB extension when it disabled. 2015-06-12 15:35:20 +03:00
who-me
031d14e320 Update qBittorrent.appdata.xml
Usage of the <updatecontact/> breaks validation. The correct tag is <update_contact/> as per info on this page:
http://www.freedesktop.org/software/appstream/docs/chap-Metadata.html#tag-update_contact
2015-06-12 13:48:53 +03:00
Chocobo1
817b595222 Fix potential negative loop bound.
QTorrentHandle::num_files() could return -1 in these cases.
2015-06-12 17:09:22 +08:00
Vladimir Golovnev (Glassez)
56df8c2dd0 Fix time_t 0 special meaning.
Return null QDateTime object when converting from 0 time_t value.
2015-06-12 09:36:01 +03:00
ngosang
3715e8d2c8 Change default preferences 2015-06-12 02:09:01 +02:00
ngosang
ad2a18b3bc Changes in User-Agent 2015-06-12 01:30:01 +02:00
ngosang
3eb61cfe83 Cppcheck: scope reduction & unused variables 2015-06-12 01:16:21 +02:00
DoumanAsh
1222dab6f8 [search engine] Remove python3 cache during updateNova() 2015-06-12 01:30:35 +03:00
sledgehammer999
8897001567 Merge pull request #2844 from ngosang/search_version
[Search engine] Show the version of search engines
2015-06-12 01:20:23 +03:00
ngosang
930161a0dd [Search engine] Show the version of search engines 2015-06-11 23:37:50 +02:00
sledgehammer999
3aa0a845cd Merge pull request #2892 from glassez/bittorrent
Core classes redesign (Issue #2433).
2015-06-11 23:54:05 +03:00
sledgehammer999
cc8419d344 Fix python detection from reigstry when multiple versions are installed. Update fallback mechanism for newer versions. 2015-06-11 23:45:18 +03:00
sledgehammer999
f3dd93a42c Merge pull request #2832 from pmzqla/rss-liveupdate
Update matching RSS articles while editing rules
2015-06-11 22:56:31 +03:00
sledgehammer999
13da85e859 Merge pull request #3164 from ngosang/demonoid
[search engine] Add Demonoid search engine
2015-06-11 22:39:44 +03:00
ngosang
cd5f904b53 Minor fixes in search engines 2015-06-11 19:06:29 +02:00
ngosang
274cde0396 [search engine] Add Demonoid search engine 2015-06-11 18:24:18 +02:00
sledgehammer999
3d40834c57 Merge pull request #2550 from DoumanAsh/multiprocessor_search
[search engine] Replace threading with multiprocessing
2015-06-11 19:14:11 +03:00
DoumanAsh
920aefddde [search engine] Final enhancements. 2015-06-11 07:52:27 +03:00
DoumanAsh
7dafb384e9 [search engine] Cosmetic update TorrentReactor 2015-06-11 07:47:39 +03:00
DoumanAsh
2fc1487603 [search engine] re-factoring of code 2015-06-11 07:47:37 +03:00
DoumanAsh
d6d0f422f5 [search engine] engines update 2015-06-11 07:45:55 +03:00
DoumanAsh
bef8106d0f [search engine] Nova2 multiprocessing 2015-06-11 07:45:53 +03:00
sledgehammer999
e502ce38ec Merge pull request #2670 from DoumanAsh/safe_url_retrieve
[search engine] Exception free url_retrieve
2015-06-11 02:22:02 +03:00
Vladimir Golovnev (Glassez)
7d73bddfd2 Split some "header only" sources. 2015-06-10 10:58:20 +03:00
DoumanAsh
86a0eaf317 Exception free retrieve_url()
Set 2 second timeout and handle any possible connection error
Return empty string to engine in case of connection exception
2015-06-10 08:15:23 +03:00
Vladimir Golovnev (Glassez)
5f288d228d Fix coding style (Issue #2192). 2015-06-09 21:30:57 +03:00
Vladimir Golovnev (Glassez)
191cdc2849 Move utilities to core/utils folder.
Also move the names to Utils namespace.
2015-06-09 21:30:56 +03:00
Vladimir Golovnev (Glassez)
427688cb34 Remove unused sources. 2015-06-09 21:30:53 +03:00
Vladimir Golovnev (Glassez)
d16d1fdb3a Redesign main core classes. 2015-06-09 21:30:42 +03:00
sledgehammer999
832272bf3a Merge pull request #2672 from DoumanAsh/abort_search_on_exit
Aborting search engine process during closure. Close #2671
2015-06-09 01:49:36 +03:00
sledgehammer999
d87cea1fb7 Merge pull request #2880 from Chocobo1/alluppercase
Use AllUppercase for label text
2015-06-08 01:41:01 +03:00
sledgehammer999
dabbc49c20 Merge pull request #2882 from pmzqla/openfile-enter
Allow to Open files from the properties pane by pressing "Enter"
2015-06-08 01:22:40 +03:00
sledgehammer999
9daf9e612b Merge pull request #2935 from Chocobo1/add_tray_menu
Add "Add link to torrent" menu in TrayIconMenu. Closes #2918.
2015-06-08 00:51:38 +03:00
sledgehammer999
46e2e5342b Merge pull request #2996 from Chocobo1/tray_icon
Enable to choose dark/light tray icons on all platforms.
2015-06-03 23:59:16 +03:00
sledgehammer999
c682d87a65 Merge pull request #2999 from LazyBui/master
Treating Alt Global Rate Limits Like Regular Global Rate Limits
2015-06-03 23:48:13 +03:00
sledgehammer999
101b0ee58e Merge pull request #3011 from ngosang/start_minimize
Fix Start Minimized checkbox in Options
2015-06-03 23:07:32 +03:00
Vladimir Golovnev (Glassez)
60c0939e05 Fix coding style (Issue #2192).
Also split filesystemwatcher.h into .h/.cpp files.
2015-06-03 22:11:44 +03:00
Vladimir Golovnev (Glassez)
d32bb52390 Don't add core to INCLUDEPATH. 2015-06-03 22:11:43 +03:00
Vladimir Golovnev (Glassez)
4b5e7e6168 Move network related code to core/net. 2015-06-03 22:11:41 +03:00
Vladimir Golovnev (Glassez)
3eeed813d6 Implement new download manager. 2015-06-03 22:11:40 +03:00
Vladimir Golovnev (Glassez)
f1bce0b8e0 Fix downloadthread.* coding style (Issue #2192). 2015-06-03 22:11:39 +03:00
Vladimir Golovnev (Glassez)
98dfb6302d Fix shutdownconfirm.* coding style (Issue #2192). 2015-06-03 22:11:38 +03:00
Vladimir Golovnev (Glassez)
d87a9bf7ec Move GUI-related sources into gui subdir. 2015-06-03 22:11:36 +03:00
sledgehammer999
2b7c47c789 Merge pull request #3092 from Chocobo1/focus_default
Change default focus button in various dialog, closes #3085
2015-06-03 21:35:17 +03:00
sledgehammer999
bafb189244 Merge pull request #3136 from Chocobo1/exit
Change option text "Confirmation on exit when torrents are active"
2015-06-03 21:05:00 +03:00
Chocobo1
ab91fb87ea Change option text "Confirmation on exit when torrents are active" 2015-06-03 13:25:36 +08:00
sledgehammer999
2ad10ea47e Merge pull request #3006 from ngosang/translate_search
Make strings translatable in search engine
2015-06-01 17:08:37 +03:00
sledgehammer999
fc28f261cf Merge pull request #2534 from ngosang/disable_chbox
Disable Auto piece size checkbox when creating a new torrent
2015-06-01 16:55:09 +03:00
sledgehammer999
a84518d69f Merge pull request #2542 from ngosang/search_tab
Change width of columns in search tab. Closes #764
2015-06-01 16:33:31 +03:00
sledgehammer999
17cba898e9 Merge pull request #3005 from ngosang/wasted
Web UI: Display wasted data with friendly units. Closes #2994
2015-06-01 16:03:59 +03:00
sledgehammer999
736f20538d Merge pull request #3040 from ngosang/webui_global_slot
Web UI: New config - Global maximum number of upload slots. Closes #2997
2015-06-01 15:57:44 +03:00
sledgehammer999
6cee7483ba Merge pull request #3041 from ngosang/webui_fix_torrentinfo
Web UI: Fix Max connections and Time active in transfer panel. Closes #2993
2015-06-01 15:26:50 +03:00
sledgehammer999
50a5e830ac Merge pull request #3086 from ngosang/webui_titlebar
Web UI: Changes in title bar, translatable strings and style
2015-06-01 15:21:57 +03:00
sledgehammer999
81b3517166 Merge pull request #3021 from ngosang/improve_torrentz
[search engine] Improve torrentz engine to return more results
2015-06-01 13:32:58 +03:00
sledgehammer999
14b5d15268 Merge pull request #3020 from ngosang/fix_piratebay
[search engine] Fix thepiratebay engine. Closes #3012
2015-06-01 13:29:59 +03:00
Chocobo1
e75de01809 Set default focus to no button in exit confirm box 2015-05-26 15:03:42 +08:00
Chocobo1
a29f2dcfaa Set default focus to ok button in add new torrent dlg 2015-05-24 15:12:07 +08:00
Chocobo1
2b2bc11d7d Set default focus to cancel button in delete confirm dlg, closes #3085 2015-05-24 15:11:37 +08:00
ngosang
7129ad47f4 Web UI: Minor changes in style 2015-05-23 22:18:52 +02:00
ngosang
dcdb319653 Web UI: Complete translatable strings 2015-05-23 20:35:25 +02:00
ngosang
c5ce99ebec Web UI: Changes in title bar 2015-05-23 19:20:04 +02:00
ngosang
e46c238f15 [search engine] Fix thepiratebay. Closes #3012 2015-05-20 08:01:41 +02:00
LazyBui
23ec562375 Making alternate download/upload configuration behave like global download/upload configuration so as to allow boundless down/up 2015-05-17 12:58:29 -05:00
sledgehammer999
2c1d76c87f Merge pull request #3027 from ngosang/fix_webui_all
Web UI: Fix resumeAll and pauseAll. Closes #3016
2015-05-17 18:44:11 +03:00
sledgehammer999
d222dece92 Merge pull request #3039 from ngosang/webui_relative_urls
Web UI: Fix login and logout relative URLs. Closes #3038
2015-05-17 18:43:38 +03:00
ngosang
8b06f72a94 Web UI: Fix Max connections and Time active in transfer information 2015-05-17 15:47:37 +02:00
ngosang
2e05777dc5 Web UI: New config - Global maximum number of upload slots 2015-05-17 14:40:34 +02:00
ngosang
dd71355e8a Web UI: Fix login and logout relative URLs 2015-05-17 13:48:06 +02:00
sledgehammer999
c92eb1b17d Merge pull request #3019 from Chocobo1/icons_path
Fix wrong path in .ui files
2015-05-17 12:37:03 +03:00
ngosang
a90ec4cce7 Web UI: Fix resumeAll and pauseAll. Closes #3016 2015-05-15 22:49:03 +02:00
Chocobo1
f1c2eae264 Fix wrong path for icons.qrc 2015-05-16 01:08:45 +08:00
ngosang
28fcbe9bc5 [search engine] Improve torrentz engine to return more results 2015-05-15 18:34:28 +02:00
ngosang
b18138bad0 Change width of columns in search tab. Closes #764 2015-05-15 14:25:51 +02:00
ngosang
0ef728d385 Fix Start Minimized checkbox in Options 2015-05-14 21:48:09 +02:00
ngosang
bd6afc2d86 Make strings translatable in seach engine 2015-05-14 14:39:30 +02:00
ngosang
de3c84bd0b Web UI: Display wasted data with friendly units. Closes #2994 2015-05-14 13:35:48 +02:00
sledgehammer999
e788445fe2 Bump to 3.3.0alpha 2015-05-13 23:33:22 +03:00
sledgehammer999
88237fbd1e Update Copyright year. 2015-05-13 23:23:53 +03:00
sledgehammer999
6fba6796b8 Fix typo in configure script. 2015-05-13 23:04:12 +03:00
sledgehammer999
2a2cb313cf Merge pull request #2990 from LazyBui/master
Removing the confusion caused by moving GeoIP code/.dat
2015-05-13 22:58:32 +03:00
Chocobo1
30f21259f8 Enable to choose dark/light tray icons on all platforms. 2015-05-13 21:50:15 +08:00
LazyBui
be62c34e46 Removing the confusion caused by moving GeoIP code/.dat to a different directory 2015-05-13 00:15:10 -05:00
sledgehammer999
e2ac4ebf9d Merge pull request #2977 from pmzqla/configure-whitespace
configure: don't fail when $CPPFLAGS starts with a white space
2015-05-11 19:03:57 +03:00
Gabriele
b67a10c4a1 configure: don't fail when $CPPFLAGS starts with a white space 2015-05-11 13:49:20 +02:00
sledgehammer999
fc52248bf7 Correctly detect FreeBSD when configuring.
Thanks to yurivict for helping.
Closes #2962.
2015-05-11 00:29:46 +03:00
sledgehammer999
4725022f7e Fix configure typo. 2015-05-11 00:29:42 +03:00
sledgehammer999
a3574d3e28 Merge pull request #2846 from Noctem/fixVariableNames
Fix variable names
2015-05-10 17:53:26 +03:00
Chocobo1
04300c11c3 Hookup to Coverity Scan, Closes #2601 2015-05-10 15:07:36 +08:00
Chocobo1
1d6263385b Use AllUppercase for label text 2015-05-10 14:13:25 +08:00
DoumanAsh
62776df9e1 Aborting search engine process during closure. Close #2671 2015-05-05 19:29:13 +03:00
Chocobo1
72c5bce6a4 Add "Add link to torrent" menu in TrayIconMenu. Closes #2918. 2015-05-04 00:59:00 +08:00
Gabriele
41fa59f164 Allow to Open files from the properties pane by pressing "Enter"
Allow to open only one file at a time and ignore keypresses when
multiple items are selected.
2015-04-16 18:50:11 +02:00
David Christenson
307ae459f2 Fix variable names
Change undeclared identifiers `running_` and `paramsQueue_` to their
proper names.
2015-04-07 20:49:45 -06:00
Gabriele
027a08c92e Update matching RSS articles while editing rules
Save the rules as soon as they are edited so that the matching
articles tree is immediately updated.

Closes #2829.
2015-04-04 19:21:33 +02:00
Chocobo1
1037d7f335 Webui: add delay in shutdown command in order to send out response msg 2015-03-30 13:50:53 +08:00
Chocobo1
3e6706a371 Don't close downloadFromURL dialog when showing empty url warning 2015-03-09 15:34:53 +08:00
Gabriele
48c1bd58dd Allow to copy all the trackers with a keyboard shortcut
If multiple trackers are selected, Ctrl+C will copy only one of them
while the context menu will copy all of them. Fix this inconsistency.

Closes #2675.
2015-03-08 12:50:22 +01:00
Mayank Asthana
cf89d892c6 Download-from-URL textbox changes focus on tab key 2015-03-03 00:27:16 +05:30
ngosang
d206b00a88 Disable Auto piece size when creating a new torrent 2015-02-11 00:53:42 +01:00
347 changed files with 189834 additions and 104851 deletions

View File

@@ -1,18 +1,30 @@
language: cpp
os:
- linux
- osx
osx_image: xcode7
env:
matrix:
# Uncomment when Travis upgraded "Ubuntu 12.04 LTS" to a newer version whose repo will have a more up-to-date libtorrent package
#- lt_branch=dist gui=true
#- lt_branch=dist gui=false
- lt_branch=RC_0_16 gui=true
- lt_branch=RC_0_16 gui=false
- lt_branch=RC_1_0 gui=true
- lt_branch=RC_1_0 gui=false
- lt_branch=RC_1_0 gui=true qt=4
- lt_branch=RC_1_0 gui=true qt=5
- lt_branch=RC_1_0 gui=false qt=4
- lt_branch=RC_1_0 gui=false qt=5
global:
- secure: "OI9CUjj4lTb0HwwIZU5PbECU3hLlAL6KC8KsbwohG8/O3j5fLcnmDsK4Ad9us5cC39sS11Jcd1kDP2qRcCuST/glVNhLkcjKkiQerOfd5nQ/qL4JYfz/1mfP5mdpz9jHKzpLUIG+TXkbSTjP6VVmsb5KPT+3pKEdRFZB+Pu9+J8="
- coverity_branch: coverity_scan
matrix:
exclude:
- os: linux
env: lt_branch=RC_1_0 gui=true qt=5
- os: linux
env: lt_branch=RC_1_0 gui=false qt=5
branches:
except:
- search_encoding_windows
@@ -25,6 +37,7 @@ notifications:
# container-based builds
sudo: false
# TODO: osx builder does not enable cache yet, see: https://github.com/travis-ci/travis-ci/issues/4011
cache:
directories:
- $HOME/.ccache
@@ -34,63 +47,75 @@ addons:
project:
name: "qbittorrent/qBittorrent"
description: "Build submitted via Travis CI"
build_command_prepend: "./bootstrap.sh && ./configure $qbtconf"
build_command_prepend: "./bootstrap.sh && ./configure $qbtconf && echo QMAKE_CC=$CC >> conf.pri && echo QMAKE_CXX=$CXX >> conf.pri"
build_command: make
branch_pattern: $coverity_branch
notification_email: sledgehammer999@qbittorrent.org
apt:
sources:
# sources list: https://github.com/travis-ci/apt-source-whitelist/blob/master/ubuntu.json
- ubuntu-toolchain-r-test
- boost-latest
packages:
# packages list: https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise
- autoconf
- automake
- colormake
- g++-4.8
- libssl-dev
- libboost-dev
- libboost-system-dev
- libgeoip-dev
- libboost1.55-dev
- libboost-system1.55-dev
- libqt4-dev
# Uncomment when Travis upgraded "Ubuntu 12.04 LTS" to a newer version whose repo will have a more up-to-date libtorrent package
#- libtorrent-rasterbar6
#- libboost-filesystem-dev
before_install:
# Only allow specific build for coverity scan, others will stop
- if [ "$TRAVIS_BRANCH" = "$coverity_branch" ] && ! [[ "$lt_branch" == "RC_1_0" && "$gui" == "true" ]]; then exit ; fi
- if [ "$TRAVIS_BRANCH" = "$coverity_branch" ] && ! [ "$TRAVIS_OS_NAME" = "linux" -a "$lt_branch" = "RC_1_0" -a "$gui" = true ]; then exit ; fi
- shopt -s expand_aliases
- if ! [ "$TRAVIS_BRANCH" = "$coverity_branch" ]; then dpkg-query -L ccache && export PATH="/usr/lib/ccache/:$PATH" ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then export CC=gcc-4.8 CXX=g++-4.8 ; fi
- if [ "$TRAVIS_BRANCH" != "$coverity_branch" -a "$TRAVIS_OS_NAME" = "linux" ]; then dpkg-query -L ccache && export PATH="/usr/lib/ccache/:$PATH" ; fi
- alias make="colormake -j3" # Using nprocs/2 sometimes may fail (gcc is killed by system)
- libt_path="$HOME/libt_install"
- qbt_path="$HOME/qbt_install"
- ltconf="$ltconf --prefix="$libt_path" --with-libgeoip=system"
- qbtconf="$qbtconf --prefix="$qbt_path" PKG_CONFIG_PATH="$libt_path/lib/pkgconfig":$PKG_CONFIG_PATH"
- ltconf="$ltconf --prefix="$libt_path" --disable-geoip"
- qbtconf="$qbtconf --prefix="$qbt_path" --with-qt4 PKG_CONFIG_PATH="$libt_path/lib/pkgconfig":$PKG_CONFIG_PATH"
# Options for specific branches
- if [[ "$lt_branch" == "RC_0_16" ]]; then qbtconf="$qbtconf --with-libtorrent-rasterbar0.16" ; fi
# Also setup a virtual display for after_success target when gui == true
- if ! $gui; then qbtconf="$qbtconf --disable-gui" ; else 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
- if [ "$gui" = false ]; then qbtconf="$qbtconf --disable-gui" ;
elif [ "$TRAVIS_OS_NAME" = "linux" ]; 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
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then qbtconf="$qbtconf --disable-qt-dbus" ; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ] && [ "$qt" = 5 ]; then qbtconf="$qbtconf --with-qt4=no" ; fi
# Print settings
- echo $lt_branch
- echo $gui
- echo $ltconf
- echo $qbtconf
- ccache -V && ccache --show-stats && ccache --zero-stats
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then ccache -V && ccache --show-stats && ccache --zero-stats ; fi
install:
- if ! [ "$lt_branch" == "dist" ]; then cd "$HOME" && pwd && git clone --depth 1 https://github.com/arvidn/libtorrent.git --branch $lt_branch --single-branch ; fi
- if ! [ "$lt_branch" == "dist" ]; then cd libtorrent && ./autotool.sh && ./configure $ltconf && make install && cd "$TRAVIS_BUILD_DIR" ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" -a "$lt_branch" != "dist" ]; then cd "$HOME" && pwd && git clone --depth 1 https://github.com/arvidn/libtorrent.git --branch $lt_branch ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" -a "$lt_branch" != "dist" ]; then cd libtorrent && ./autotool.sh && ./configure $ltconf && make install && cd "$TRAVIS_BUILD_DIR" ; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update > /dev/null && brew install colormake libtorrent-rasterbar; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ] && [ "$qt" = 4 ]; then brew install qt; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ] && [ "$qt" = 5 ]; then brew install qt5 && brew link --force qt5; fi
script:
- if [ "$TRAVIS_BRANCH" = "$coverity_branch" ]; then exit ; fi # Skip usual build when running coverity scan
- ./bootstrap.sh && ./configure $qbtconf
- make install
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then echo QMAKE_CC=$CC >> conf.pri && echo QMAKE_CXX=$CXX >> conf.pri ; fi
- make && make install
after_success:
- cd "$qbt_path/bin"
- export LD_PRELOAD="$libt_path/lib/libtorrent-rasterbar.so:$LD_PRELOAD"
- if $gui ; then ./qbittorrent --version ; else ./qbittorrent-nox --version ; fi
- if [ "$gui" = true ]; then qbt_exe="qbittorrent" ; else qbt_exe="qbittorrent-nox" ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd "$qbt_path/bin" && export LD_PRELOAD="$libt_path/lib/libtorrent-rasterbar.so:$LD_PRELOAD" ; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then cd "src/$qbt_exe.app/Contents/MacOS" ; fi
- ./$qbt_exe --version
after_script:
- ccache --show-stats
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then ccache --show-stats ; fi

View File

@@ -1,7 +1,7 @@
[main]
host = https://www.transifex.com
[qbittorrent.qbittorrent_v3_2_x]
[qbittorrent.qbittorrent_v3_3_x]
file_filter = src/lang/qbittorrent_<lang>.ts
source_file = src/lang/qbittorrent_en.ts
source_lang = en

View File

@@ -10,18 +10,20 @@ int myFunction(int a)
//code
}
myClass::myClass(int *parent)
void myFunction() {} // empty body
MyClass::MyClass(int *parent)
: m_parent(parent)
{
//initialiaze
//initialize
}
int myClass::myMethod(int a)
int MyClass::myMethod(int a)
{
//code
}
class myOtherClass
class MyOtherClass
{
public:
//code
@@ -31,10 +33,18 @@ private:
//code
};
namespace id
namespace Name
{
//code
}
// Lambdas
[](int arg1, int arg2) -> bool { return arg1 < arg2; }
[this](int arg)
{
this->acc += arg;
}
```
#### b. Other code blocks ####
@@ -75,6 +85,12 @@ default:
}
```
#### d. single-line blocks (lambdas, initializer lists etc.) ####
```c++
{} // empty - space before {
{ body } // spaces around { and before }
```
### 2. If blocks ###
#### a. Multiple tests ####
```c++
@@ -119,16 +135,16 @@ Generally it will depend on the particular piece of code and would be determined
### 4. File encoding and line endings.###
UTF-8 and Unix-like line ending (LF). Unless some platform speficic files need other encodings/line endings.
UTF-8 and Unix-like line ending (LF). Unless some platform specific files need other encodings/line endings.
### 5. Initialization lists.###
Initialization lists should be vertical. This will allow for more easily readable diffs. The inilization 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.
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)
: priv_a(a)
, priv_b(b)
, priv_c(c)
, priv_d(d)
: m_a(a)
, m_b(b)
, m_c(c)
, m_d(d)
{
//code
}
@@ -137,7 +153,7 @@ myClass::myClass(int a, int b, int c, int d)
### 6. Enums.###
Enums should be vertical. This will allow for more easily readable diffs. The members should be indented.
```c++
enum days
enum Days
{
Monday,
Tuesday,
@@ -149,7 +165,41 @@ enum days
};
```
### 7. Misc.###
### 7. Names.###
All names should be camelCased.
#### a. Type names and namespaces ####
Type names and namespaces start with Upper case letter (except POD types).
```c++
class ClassName {}
struct StructName {}
enum EnumName {}
typedef QList<ClassName> SomeList;
namespace NamespaceName
{
}
```
#### b. Variable names ####
Variable names start with lower case letter.
```c++
int myVar;
```
#### c. Private member variable names ####
Private member variable names start with lower case letter and should have ```m_``` prefix.
```c++
class MyClass
{
int m_myVar;
}
```
### 8. Misc.###
* Line breaks for long lines with operation:

158
Changelog
View File

@@ -1,110 +1,54 @@
* Sat Aug 01 2015 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.2.2
- FEATURE: Allow to force reannounce DHT too (Chocobo1)
- FEATURE: Implement an option to disable confirmation of torrent recheck (blaxspirit)
- FEATURE: Allow to copy all the trackers with a keyboard shortcut (pmzqla)
- BUGFIX: Fix torrent renaming. Closes #3398 (ngosang)
- BUGFIX: Fix localhost address (::ffff:127.0.0.1) is not recognized when connecting to WebUI (Chocobo1)
- BUGFIX: Fix '&' character in label name becomes accelerator key, closes #3454. (Chocobo1)
- BUGFIX: Fix HTTP header parsing when torrent filename contains a semicolon. Closes #3511.
- BUGFIX: Fix installing search plugin from local file. (sledgehammer999)
- BUGFIX: Fix installing search plugin by drag-n-dropping file. (sledgehammer999)
- COSMETIC: Update color scheme of completed.png icon. (sledgehammer999)
- COSMETIC: Fix printing of the copyright symbol in the About dialog. (sledgehammer999)
- COSMETIC: Minor changes in Preview File dialog (ngosang)
- COSMETIC: Add Force Resume icon (ngosang)
- COSMETIC: Add count of unread items to RSS tab label (pmzqla)
- WEBUI: Ports between 1 and 65535 as in the GUI. Closes #1602 (ngosang)
- WEBUI: Fix an error in Content tab when the torrent doesn't have metadata (ngosang)
- WEBUI: New option Web UI port UPNP. Closes #3358 (ngosang)
- WEBUI: Fix API Content Types. Closes #3393 (ngosang)
- WEBUI: Fix empty trackers addition (ngosang)
- WEBUI: Torrent download from hash. Closes #1173 (ngosang)
- WEBUI: Fix sort by queue number (ngosang)
- WEBUI: Open external links in a new window/tab (ngosang)
- WEBUI: Massive increase in performance. (ngosang)
- SEARCH: Search status per tab (DoumanAsh)
- SEARCH: Remove the word 'torrent' in ExtraTorrent results (ngosang)
- SEARCH: Prefer python3 over python2 on Linux and OS X (pmzqla)
- SEARCH: Show notification if Python is not found and a search is started (pmzqla)
- SEARCH: Update link to the Windows Python installer (pmzqla)
- SEARCH: Improve checks for python. Print python version and path to log. (sledgehammer999)
- SEARCH: Improve Python detection (ngosang)
- OTHER: Improvements on the build system (Chocobo1)
- OTHER: Bump minimum libtorrent version required to 1.0.6/0.16.19. (sledgehammer999)
- OTHER: New translation: Slovenian
* Sat Jul 11 2015 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.2.1
- FEATURE: Change default preferences (ngosang)
- FEATURE: Add "Add link to torrent" menu in TrayIconMenu. Closes #2918. (Chocobo1)
- FEATURE: Allow to Open files from the properties pane by pressing "Enter" (pmzqla)
- FEATURE: Add checkbox option for IpFilterTrackers. (Chocobo1)
- FEATURE: Download-from-URL textbox change focus on tab key (Mayank Asthana)
- FEATURE: Increase priority value of "High" (pmzqla)
- FEATURE: Add 16 KiB, 8 MiB and 16 MiB piece sizes in Torrent Creator (ngosang)
- BUGFIX: Disable Auto piece size when creating a new torrent (ngosang)
- BUGFIX: Set default focus to cancel button in delete confirm dlg, closes #3085 (Chocobo1)
- BUGFIX: Set default focus to ok button in add new torrent dlg (Chocobo1)
- BUGFIX: Set default focus to no button in exit confirm box (Chocobo1)
- BUGFIX: Fix Start Minimized checkbox in Options (ngosang)
- BUGFIX: Remove limits on alternative speeds setting (LazyBui)
- BUGFIX: Fix sorting torrents by ETA (pmzqla)
- BUGFIX: Improve ratio calculation formula. Closes #3096. (Chocobo1)
- BUGFIX: Clear missing files flag when resuming or force rechecking. Fixes issues in #2750. (sledgehammer999)
- BUGFIX: Delete tempfile when downloading favicon.ico. Closes #3257. (sledgehammer999)
- BUGFIX: Don't close downloadFromURL dialog when showing empty url warning (Chocobo1)
- BUGFIX: Minimize to tray only if the relevant option is enabled. (sledgehammer999)
- BUGFIX: Update disk space label after changing partition, closes #3309. (Chocobo1)
- BUGFIX: Don't use a default upload limit. Closes #3275. (sledgehammer999)
- BUGFIX: Fix Properties bar size when started minimized to tray. Closes #3206. (sledgehammer999)
- COSMETIC: Change option text "Confirmation on exit when torrents are active" (Chocobo1)
- COSMETIC: Enable to choose dark/light tray icons on all platforms. (Chocobo1)
- COSMETIC: Use AllUppercase for label text (Chocobo1)
- COSMETIC: changes in typography (ngosang)
- COSMETIC: Menu revamp (Chocobo1)
- COSMETIC: Revamp general tab info (Chocobo1)
- COSMETIC: Better update message for users (Chocobo1)
- COSMETIC: Fix ugly 'C++' wrapping in About dialog. (glassez)
- WEBUI: Fix login and logout relative URLs (ngosang)
- WEBUI: Fix resumeAll and pauseAll. Closes #3016 (ngosang)
- WEBUI: Changes in title bar (ngosang)
- WEBUI: Complete translatable strings (ngosang)
- WEBUI: Minor changes in style (ngosang)
- WEBUI: Fix Max connections and Time active in transfer information (ngosang)
- WEBUI: New config - Global maximum number of upload slots (ngosang)
- WEBUI: Display wasted data with friendly units. Closes #2994 (ngosang)
- WEBUI: add delay in shutdown command in order to send out response msg (Chocobo1)
- WEBUI: Option to hide Top Toolbar (ngosang)
- WEBUI: Reorder the tabs/groups in Options window (ngosang)
- WEBUI: Add new options (ngosang)
- WEBUI: Increase API_VERSION due to changes in #3279, #3197, #3226 and #3040 (ngosang)
- WEBUI: Add Web Seeds (HTTP Sources) tab (ngosang)
- WEBUI: Don't update the tabs if tab's panel is collapsed (ngosang)
- WEBUI: Fix alternative global rate limits. (ngosang)
- 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 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)
- SEARCH: Minor fixes in search engines (ngosang)
- SEARCH: Show the version of search engines (ngosang)
- SEARCH: Update Legit Torrent to remove sgmllib (DoumanAsh)
- SEARCH: Update KickassTorrents (ngosang)
- SEARCH: Update BTDigg (ngosang)
- SEARCH: Update Torrentz (ngosang)
- SEARCH: Update ExtraTorrent (ngosang)
- SEARCH: Update TorrentReactor (ngosang)
- SEARCH: Fix Python 2 implementation of Torrentz (ngosang)
- SEARCH: Cosmetic changes in search engine (ngosang)
- SEARCH: Fix column sort in search engine. Closes #2621 (ngosang)
- RSS: Update matching RSS articles while editing rules (pmzqla)
- WINDOWS: Fix python detection from registry when multiple versions are installed (sledgehammer999)
- LINUX: Fixes Linux issue for when the theme doesn't have a corresponding icon. (sledgehammer999)
- OTHER: Correctly detect FreeBSD when configuring. (sledgehammer999, yurivict)
- OTHER: Add translator to credits.
- OTHER: New translation: Indonesian.
- OTHER: Split Chinese locales into Chinese Simplified, Chinese Traditional(Taiwan), Chinese Traditional(Hong Kong). (sledgehammer999)
* Sun Nov 29 2015 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.3.0
- FEATURE: Huge core code refactoring. Problems with labels, temp folders etc should be eliminated. Smoother UI should be observed too. (glassez)
- FEATURE: Speed graph (Anton Lashkov)
- FEATURE: Add multiple peers in Peers addition dialog. Closes #1563, #2245, #3133, #1419, #3287, #1419 (ngosang)
- FEATURE: Allow to copy all peers with a keyboard shortcut (ngosang)
- FEATURE: Use GeoIP2 database, allows for country resolution of IPv6 peers. It is no longer embedded in the program but downloaded and updated monthly. (glassez)
- FEATURE: Add more "Run External Program" parameters, closes #3053, #238, #1291, #1522. (Chocobo1, glassez)
- FEATURE: Add an option to allow the use of proxies only for torrents. Closes #2701. (pmzqla)
- FEATURE: Detect network interface state changes. It should detect VPN connection resets. (Pawel Polewicz)
- FEATURE: Switch to using c++11 (glassez)
- FEATURE: Automatically add trackers to new downloads. (ngosang)
- FEATURE: You can now choose the path to download for watched folders. (dsimakov, sledgehammer999)
- FEATURE: Switch to Qt5 by default.
- BUGFIX: Fix progress calculation in Content tab. Closes #2639 Closes #2752 (ngosang)
- BUGFIX: Fix label filter. Closes #3429. (glassez)
- BUGFIX: Fix "Run External Program Launches too Early" issue, closes #2107. (Chocobo1)
- BUGFIX: Don't remove torrent contents parent folder, even it is empty. Closes #2244. (Chocobo1)
- BUGFIX: Always apply filter for manually banned IPs. Related #3988. (sledgehammer999)
- BUGFIX: Fix reporting of tracker status. Closes #3101. (sledgehammer999)
- BUGFIX: Don't connect to "any interface" when the configured network interface is missing. Closes #3943, #2741, #1159, #844 and #143. (sledgehammer999)
- BUGFIX: Fix reordering of first column with Qt5. Closes #2835. (sledgehammer999)
- COSMETIC: Add back "qBittorrent" in program updater title, closes #3549. (Chocobo1)
- COSMETIC: Use infinity symbol rather than -1 for nb_connections (pmzqla)
- COSMETIC: Move uTP options to it's own section (Chocobo1)
- COSMETIC: Fix availability bar & progress bar height being too small on high DPI displays (Chocobo1)
- COSMETIC: Fix availability label & progress label clipped on high DPI displays, closes #3237. (Chocobo1)
- COSMETIC: Add tooltips/legend for availability bar & progress bar (Chocobo1)
- COSMETIC: Use theme color for background in PropertiesWidget (Chocobo1)
- COSMETIC: Replace horizontal line with border in bottom panel (Chocobo1)
- COSMETIC: Various visual changes in the side panel. (Chocobo1)
- COSMETIC: Use thin border for transfer list (Chocobo1)
- COSMETIC: Make URL in "Add Torrent File..." clickable. Closes #3928. (Chocobo1)
- COSMETIC: New view for errored torrents. (sledgehammer999)
- WEBUI: Add information in General tab (ngosang)
- WEBUI: Reorder "Super seeding mode" option in right click menu (ngosang)
- WEBUI: Clean up JavaScript code (ngosang)
- WEBUI: Added labels support. #648 (Felipe Barriga Richards, ngosnag)
- WEBUI: Fix accessing the WebUI through IPv6 (ngosang)
- WEBUI: Bump WebUI API_VERSION to 6.
- WEBUI: Change selected color to differentiate from the progressbar. (Daniel Peukert, ngosang)
- SEARCH: Add "Copy description page URL" button in search tab. Closes #2371. (pmzqla)
- SEARCH: Add https_proxy env variable. This forces Python to use the HTTP proxy for HTTPS connections. (pmzqla)
- SEARCH: Detect new plugin URL from clipboard (ngosang)
- SEARCH: Update Torrentz trackers (ngosang)
- WINDOWS: Fix german translation of the installer (netswap)
- NOX: Don't ask the user questions in nox build when in non-interactive mode. Closes #3875. (sledgehammer999)
- OTHER: Fixed typos, spelling correction (dartraiden)
- OTHER: Fix need for restart to enable/disable peer countries resolution. (glassez)
- OTHER: Unload the GeoIP db when disabled. (sledgehammer999)
- OTHER: Reduce max value of "Disk cache size" to 1536MB for 32bit. Closes to #4028. (Chocobo1)
- OTHER: Make "Download in sequential order" and "Download first and last piece first" options independent. (glassez)
* Sun May 10 2015 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.2.0
- FEATURE: Show actual protocol for listen success/failure in the log. Needs libtorrent v1.0.0 (Gelmir)

10
INSTALL
View File

@@ -14,15 +14,11 @@ qBittorrent - A BitTorrent client in C++ / Qt4
- pkg-config executable
- libtorrent-rasterbar by Arvid Norberg (>= 0.15.0)
- 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.
- libboost 1.34.x (libboost-filesystem°) + libasio
or
- libboost >= 1.35.x (libboost-system, libboost-filesystem°)
°libboost-filesystem is not needed if libtorrent-rasterbar >= v0.16.x is used
- libboost >= 1.35.x (libboost-system)
- python >= 2.3 (needed by search engine)
* Run time only dependency
@@ -44,7 +40,7 @@ qBittorrent - A BitTorrent client in C++ / Qt4
- pkg-config executable
- libtorrent-rasterbar by Arvid Norberg (>= v0.15.0)
- 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.

View File

@@ -1,7 +1,7 @@
qBittorrent - A BitTorrent client in Qt
------------------------------------------
[![Build Status](https://travis-ci.org/qbittorrent/qBittorrent.svg?branch=v3_2_x)](https://travis-ci.org/qbittorrent/qBittorrent)
[![Build Status](https://travis-ci.org/qbittorrent/qBittorrent.svg?branch=master)](https://travis-ci.org/qbittorrent/qBittorrent)
[![Coverity Status](https://scan.coverity.com/projects/5494/badge.svg)](https://scan.coverity.com/projects/5494)
********************************
### Description:
@@ -32,6 +32,9 @@ http://www.qbittorrent.org
or our wiki here:
http://wiki.qbittorrent.org
Use the forum for troubleshooting before reporting bugs:
http://forum.qbittorrent.org
Please report any bug (or feature request) to:
http://bugs.qbittorrent.org

View File

@@ -26,7 +26,7 @@ How to build
First you need to create the conf.pri file in the same dir as this readme.os2 is.
the conf.pri file has the following content:
##### conf.pri content beginn #####
##### conf.pri content begin #####
BINDIR = ./bin
INCDIR = ./include
LIBDIR = ./lib

602
configure vendored
View File

@@ -601,10 +601,10 @@ EXPAND_BINDIR
EXPAND_PREFIX
zlib_LIBS
zlib_CFLAGS
qjson_LIBS
qjson_CFLAGS
libtorrent_LIBS
libtorrent_CFLAGS
qjson_LIBS
qjson_CFLAGS
BOOST_SYSTEM_LIB
BOOST_LDFLAGS
BOOST_CPPFLAGS
@@ -690,6 +690,7 @@ infodir
docdir
oldincludedir
includedir
runstatedir
localstatedir
sharedstatedir
sysconfdir
@@ -714,9 +715,7 @@ ac_user_opts='
enable_option_checking
enable_dependency_tracking
enable_silent_rules
with_qt5
with_libtorrent_rasterbar0_16
with_geoip_database_embedded
with_qt4
with_qtsingleapplication
with_qjson
enable_debug
@@ -743,10 +742,10 @@ PKG_CONFIG
PKG_CONFIG_PATH
PKG_CONFIG_LIBDIR
QT_QMAKE
libtorrent_CFLAGS
libtorrent_LIBS
qjson_CFLAGS
qjson_LIBS
libtorrent_CFLAGS
libtorrent_LIBS
zlib_CFLAGS
zlib_LIBS'
@@ -787,6 +786,7 @@ 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}'
@@ -1039,6 +1039,15 @@ 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=* \
@@ -1176,7 +1185,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
libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@@ -1329,6 +1338,7 @@ 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]
@@ -1383,14 +1393,7 @@ Optional Features:
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-qt5 Compile using Qt5 (default=no)
--with-libtorrent-rasterbar0.16
Compile using libtorrent-rasterbar 0.16.x series
(default=no)
--with-geoip-database-embedded
Embed the GeoIP database in the qBittorrent
executable (please follow instructions in
src/gui/geoip/README) (default=no)
--with-qt4 Compile using Qt4 (default=no)
--with-qtsingleapplication=[system|shipped]
Use the shipped qtsingleapplication library or the
system one (default=shipped)
@@ -1426,14 +1429,14 @@ Some influential environment variables:
directories to add to pkg-config's search path
PKG_CONFIG_LIBDIR
path overriding pkg-config's built-in search path
QT_QMAKE value of moc_location for QtCore >= 4.8.0, overriding pkg-config
QT_QMAKE value of host_bins for Qt5Core >= 5.2.0, overriding pkg-config
qjson_CFLAGS
C compiler flags for qjson, overriding pkg-config
qjson_LIBS linker flags for qjson, overriding pkg-config
libtorrent_CFLAGS
C compiler flags for libtorrent, overriding pkg-config
libtorrent_LIBS
linker flags for libtorrent, overriding pkg-config
qjson_CFLAGS
C compiler flags for qjson, overriding pkg-config
qjson_LIBS linker flags for qjson, overriding pkg-config
zlib_CFLAGS C compiler flags for zlib, overriding pkg-config
zlib_LIBS linker flags for zlib, overriding pkg-config
@@ -4176,29 +4179,11 @@ fi
# Define --wth-* and --enable-* arguments
# Check whether --with-qt5 was given.
if test "${with_qt5+set}" = set; then :
withval=$with_qt5;
# Check whether --with-qt4 was given.
if test "${with_qt4+set}" = set; then :
withval=$with_qt4;
else
with_qt5=no
fi
# Check whether --with-libtorrent-rasterbar0.16 was given.
if test "${with_libtorrent_rasterbar0_16+set}" = set; then :
withval=$with_libtorrent_rasterbar0_16;
else
with_libtorrent_rasterbar0_16=no
fi
# Check whether --with-geoip-database-embedded was given.
if test "${with_geoip_database_embedded+set}" = set; then :
withval=$with_geoip_database_embedded;
else
with_geoip_database_embedded=no
with_qt4=no
fi
@@ -4429,7 +4414,6 @@ $as_echo "yes" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
enable_qt_dbus=no
enable_geoip_database=no
QBT_ADD_CONFIG="$QBT_ADD_CONFIG nogui" ;; #(
*) :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_gui" >&5
@@ -4471,13 +4455,106 @@ $as_echo "$enable_webui" >&6; }
as_fn_error $? "Unknown option \"$enable_webui\". Use either \"yes\" or \"no\"." "$LINENO" 5 ;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether Qt5 should be enabled" >&5
$as_echo_n "checking whether Qt5 should be enabled... " >&6; }
case "x$with_qt5" in #(
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether Qt4 should be enabled" >&5
$as_echo_n "checking whether Qt4 should be enabled... " >&6; }
case "x$with_qt4" in #(
"xno") :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Core >= 5.2.0\""; } >&5
($PKG_CONFIG --exists --print-errors "Qt5Core >= 5.2.0") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
if test -n "$QT_QMAKE"; then
pkg_cv_QT_QMAKE="$QT_QMAKE"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Core >= 5.2.0\""; } >&5
($PKG_CONFIG --exists --print-errors "Qt5Core >= 5.2.0") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_QT_QMAKE=`$PKG_CONFIG --variable="host_bins" "Qt5Core >= 5.2.0" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
QT_QMAKE=$pkg_cv_QT_QMAKE
if test "x$QT_QMAKE" = x""; then :
fi
fi
as_ac_File=`$as_echo "ac_cv_file_$QT_QMAKE/qmake" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $QT_QMAKE/qmake" >&5
$as_echo_n "checking for $QT_QMAKE/qmake... " >&6; }
if eval \${$as_ac_File+:} false; then :
$as_echo_n "(cached) " >&6
else
test "$cross_compiling" = yes &&
as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
if test -r "$QT_QMAKE/qmake"; then
eval "$as_ac_File=yes"
else
eval "$as_ac_File=no"
fi
fi
eval ac_res=\$$as_ac_File
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
if eval test \"x\$"$as_ac_File"\" = x"yes"; then :
QT_QMAKE="$QT_QMAKE/qmake"
else
as_ac_File=`$as_echo "ac_cv_file_$QT_QMAKE/qmake-qt5" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $QT_QMAKE/qmake-qt5" >&5
$as_echo_n "checking for $QT_QMAKE/qmake-qt5... " >&6; }
if eval \${$as_ac_File+:} false; then :
$as_echo_n "(cached) " >&6
else
test "$cross_compiling" = yes &&
as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
if test -r "$QT_QMAKE/qmake-qt5"; then
eval "$as_ac_File=yes"
else
eval "$as_ac_File=no"
fi
fi
eval ac_res=\$$as_ac_File
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
if eval test \"x\$"$as_ac_File"\" = x"yes"; then :
QT_QMAKE="$QT_QMAKE/qmake-qt5"
else
QT_QMAKE=""
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Qt5 qmake >= 5.2.0" >&5
$as_echo_n "checking for Qt5 qmake >= 5.2.0... " >&6; }
if test "x$QT_QMAKE" != "x"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $QT_QMAKE" >&5
$as_echo "$QT_QMAKE" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
$as_echo "not found" >&6; }
fi
;; #(
"xyes") :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"QtCore >= 4.8.0\""; } >&5
($PKG_CONFIG --exists --print-errors "QtCore >= 4.8.0") 2>&5
ac_status=$?
@@ -4589,105 +4666,12 @@ else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
$as_echo "not found" >&6; }
fi
;; #(
"xyes") :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Core >= 5.2.0\""; } >&5
($PKG_CONFIG --exists --print-errors "Qt5Core >= 5.2.0") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
if test -n "$QT_QMAKE"; then
pkg_cv_QT_QMAKE="$QT_QMAKE"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Core >= 5.2.0\""; } >&5
($PKG_CONFIG --exists --print-errors "Qt5Core >= 5.2.0") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_QT_QMAKE=`$PKG_CONFIG --variable="host_bins" "Qt5Core >= 5.2.0" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
QT_QMAKE=$pkg_cv_QT_QMAKE
if test "x$QT_QMAKE" = x""; then :
fi
fi
as_ac_File=`$as_echo "ac_cv_file_$QT_QMAKE/qmake" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $QT_QMAKE/qmake" >&5
$as_echo_n "checking for $QT_QMAKE/qmake... " >&6; }
if eval \${$as_ac_File+:} false; then :
$as_echo_n "(cached) " >&6
else
test "$cross_compiling" = yes &&
as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
if test -r "$QT_QMAKE/qmake"; then
eval "$as_ac_File=yes"
else
eval "$as_ac_File=no"
fi
fi
eval ac_res=\$$as_ac_File
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
if eval test \"x\$"$as_ac_File"\" = x"yes"; then :
QT_QMAKE="$QT_QMAKE/qmake"
else
as_ac_File=`$as_echo "ac_cv_file_$QT_QMAKE/qmake-qt5" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $QT_QMAKE/qmake-qt5" >&5
$as_echo_n "checking for $QT_QMAKE/qmake-qt5... " >&6; }
if eval \${$as_ac_File+:} false; then :
$as_echo_n "(cached) " >&6
else
test "$cross_compiling" = yes &&
as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
if test -r "$QT_QMAKE/qmake-qt5"; then
eval "$as_ac_File=yes"
else
eval "$as_ac_File=no"
fi
fi
eval ac_res=\$$as_ac_File
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
if eval test \"x\$"$as_ac_File"\" = x"yes"; then :
QT_QMAKE="$QT_QMAKE/qmake-qt5"
else
QT_QMAKE=""
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Qt5 qmake >= 5.2.0" >&5
$as_echo_n "checking for Qt5 qmake >= 5.2.0... " >&6; }
if test "x$QT_QMAKE" != "x"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $QT_QMAKE" >&5
$as_echo "$QT_QMAKE" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
$as_echo "not found" >&6; }
fi
;; #(
*) :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_qt5" >&5
$as_echo "$with_qt5" >&6; }
as_fn_error $? "Unknown option \"$with_qt5\". Use either \"yes\" or \"no\"." "$LINENO" 5 ;;
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_qt4" >&5
$as_echo "$with_qt4" >&6; }
as_fn_error $? "Unknown option \"$with_qt4\". Use either \"yes\" or \"no\"." "$LINENO" 5 ;;
esac
if test "x$QT_QMAKE" = "x"; then :
as_fn_error $? "Could not find qmake" "$LINENO" 5
@@ -4700,7 +4684,7 @@ case "x$enable_qt_dbus" in #(
"xyes") :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
if test "x$with_qt5" = "xyes"; then :
if test "x$with_qt4" = "xno"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Qt5DBus >= 5.2.0" >&5
$as_echo_n "checking for Qt5DBus >= 5.2.0... " >&6; }
if test -n "$PKG_CONFIG" && \
@@ -4811,8 +4795,11 @@ $as_echo_n "checking for boostlib >= $boost_lib_version_req... " >&6; }
libsubdirs="lib"
ax_arch=`uname -m`
case $ax_arch in
x86_64|ppc64|s390x|sparc64|aarch64)
libsubdirs="lib64 lib lib64"
x86_64)
libsubdirs="lib64 libx32 lib lib64"
;;
ppc64|s390x|sparc64|aarch64|ppc64le)
libsubdirs="lib64 lib lib64 ppc64le"
;;
esac
@@ -4903,6 +4890,10 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
if test "x$succeeded" != "xyes"; then
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
BOOST_CPPFLAGS=
BOOST_LDFLAGS=
_version=0
if test "$ac_boost_path" != ""; then
if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
@@ -4915,6 +4906,11 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE"
done
if test -z "$BOOST_CPPFLAGS"; then
if test -d "$ac_boost_path/boost" && test -r "$ac_boost_path/boost"; then
BOOST_CPPFLAGS="-I$ac_boost_path"
fi
fi
fi
else
if test "$cross_compiling" != yes; then
@@ -5294,222 +5290,6 @@ $as_echo "$as_me: Boost.System LIB: $BOOST_SYSTEM_LIB" >&6;}
LIBS="$BOOST_SYSTEM_LIB $LIBS"
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile using libtorrent-rasterbar 0.16.x" >&5
$as_echo_n "checking whether to compile using libtorrent-rasterbar 0.16.x... " >&6; }
case "x$with_libtorrent_rasterbar0_16" in #(
"xno") :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libtorrent" >&5
$as_echo_n "checking for libtorrent... " >&6; }
if test -n "$libtorrent_CFLAGS"; then
pkg_cv_libtorrent_CFLAGS="$libtorrent_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtorrent-rasterbar >= 1.0.6\""; } >&5
($PKG_CONFIG --exists --print-errors "libtorrent-rasterbar >= 1.0.6") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_libtorrent_CFLAGS=`$PKG_CONFIG --cflags "libtorrent-rasterbar >= 1.0.6" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test -n "$libtorrent_LIBS"; then
pkg_cv_libtorrent_LIBS="$libtorrent_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtorrent-rasterbar >= 1.0.6\""; } >&5
($PKG_CONFIG --exists --print-errors "libtorrent-rasterbar >= 1.0.6") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_libtorrent_LIBS=`$PKG_CONFIG --libs "libtorrent-rasterbar >= 1.0.6" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test $pkg_failed = yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
libtorrent_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libtorrent-rasterbar >= 1.0.6" 2>&1`
else
libtorrent_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libtorrent-rasterbar >= 1.0.6" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$libtorrent_PKG_ERRORS" >&5
as_fn_error $? "Package requirements (libtorrent-rasterbar >= 1.0.6) were not met:
$libtorrent_PKG_ERRORS
Consider adjusting the PKG_CONFIG_PATH environment variable if you
installed software in a non-standard prefix.
Alternatively, you may set the environment variables libtorrent_CFLAGS
and libtorrent_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details." "$LINENO" 5
elif test $pkg_failed = untried; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
path to pkg-config.
Alternatively, you may set the environment variables libtorrent_CFLAGS
and libtorrent_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.
To get pkg-config, see <http://pkg-config.freedesktop.org/>.
See \`config.log' for more details" "$LINENO" 5; }
else
libtorrent_CFLAGS=$pkg_cv_libtorrent_CFLAGS
libtorrent_LIBS=$pkg_cv_libtorrent_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
CPPFLAGS="$libtorrent_CFLAGS $CPPFLAGS"
LIBS="$libtorrent_LIBS $LIBS"
fi ;; #(
"xyes") :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libtorrent" >&5
$as_echo_n "checking for libtorrent... " >&6; }
if test -n "$libtorrent_CFLAGS"; then
pkg_cv_libtorrent_CFLAGS="$libtorrent_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtorrent-rasterbar >= 0.16.19\""; } >&5
($PKG_CONFIG --exists --print-errors "libtorrent-rasterbar >= 0.16.19") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_libtorrent_CFLAGS=`$PKG_CONFIG --cflags "libtorrent-rasterbar >= 0.16.19" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test -n "$libtorrent_LIBS"; then
pkg_cv_libtorrent_LIBS="$libtorrent_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtorrent-rasterbar >= 0.16.19\""; } >&5
($PKG_CONFIG --exists --print-errors "libtorrent-rasterbar >= 0.16.19") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_libtorrent_LIBS=`$PKG_CONFIG --libs "libtorrent-rasterbar >= 0.16.19" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test $pkg_failed = yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
libtorrent_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libtorrent-rasterbar >= 0.16.19" 2>&1`
else
libtorrent_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libtorrent-rasterbar >= 0.16.19" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$libtorrent_PKG_ERRORS" >&5
as_fn_error $? "Package requirements (libtorrent-rasterbar >= 0.16.19) were not met:
$libtorrent_PKG_ERRORS
Consider adjusting the PKG_CONFIG_PATH environment variable if you
installed software in a non-standard prefix.
Alternatively, you may set the environment variables libtorrent_CFLAGS
and libtorrent_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details." "$LINENO" 5
elif test $pkg_failed = untried; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
path to pkg-config.
Alternatively, you may set the environment variables libtorrent_CFLAGS
and libtorrent_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.
To get pkg-config, see <http://pkg-config.freedesktop.org/>.
See \`config.log' for more details" "$LINENO" 5; }
else
libtorrent_CFLAGS=$pkg_cv_libtorrent_CFLAGS
libtorrent_LIBS=$pkg_cv_libtorrent_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
CPPFLAGS="$libtorrent_CFLAGS $CPPFLAGS"
LIBS="$libtorrent_LIBS $LIBS"
fi ;; #(
*) :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_libtorrent_rasterbar0_16" >&5
$as_echo "$with_libtorrent_rasterbar0_16" >&6; }
as_fn_error $? "Unknown option \"$with_libtorrent_rasterbar0_16\". Use either \"yes\" or \"no\"." "$LINENO" 5 ;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to embed the GeoIP database" >&5
$as_echo_n "checking whether to embed the GeoIP database... " >&6; }
case "x$with_geoip_database_embedded" in #(
"xno") :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
QBT_REMOVE_DEFINES="$QBT_REMOVE_DEFINES WITH_GEOIP_EMBEDDED" ;; #(
"xyes") :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
QBT_ADD_DEFINES="$QBT_ADD_DEFINES WITH_GEOIP_EMBEDDED" ;; #(
*) :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_geoip_database_embedded" >&5
$as_echo "$with_geoip_database_embedded" >&6; }
as_fn_error $? "Unknown option \"$with_geoip_database_embedded\". Use either \"yes\" or \"no\"." "$LINENO" 5 ;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which qtsingleapplication to use" >&5
$as_echo_n "checking which qtsingleapplication to use... " >&6; }
case "x$with_qtsingleapplication" in #(
@@ -5527,7 +5307,7 @@ $as_echo "$with_qtsingleapplication" >&6; }
as_fn_error $? "Unknown option \"$with_qtsingleapplication\". Use either \"system\" or \"shipped\"." "$LINENO" 5 ;;
esac
if test "x$with_qt5" = "xno"; then :
if test "x$with_qt4" = "xyes"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which qjson to use" >&5
$as_echo_n "checking which qjson to use... " >&6; }
case "x$with_qjson" in #(
@@ -5640,6 +5420,99 @@ esac
fi
pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libtorrent" >&5
$as_echo_n "checking for libtorrent... " >&6; }
if test -n "$libtorrent_CFLAGS"; then
pkg_cv_libtorrent_CFLAGS="$libtorrent_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtorrent-rasterbar >= 1.0.6\""; } >&5
($PKG_CONFIG --exists --print-errors "libtorrent-rasterbar >= 1.0.6") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_libtorrent_CFLAGS=`$PKG_CONFIG --cflags "libtorrent-rasterbar >= 1.0.6" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test -n "$libtorrent_LIBS"; then
pkg_cv_libtorrent_LIBS="$libtorrent_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtorrent-rasterbar >= 1.0.6\""; } >&5
($PKG_CONFIG --exists --print-errors "libtorrent-rasterbar >= 1.0.6") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_libtorrent_LIBS=`$PKG_CONFIG --libs "libtorrent-rasterbar >= 1.0.6" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test $pkg_failed = yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
libtorrent_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libtorrent-rasterbar >= 1.0.6" 2>&1`
else
libtorrent_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libtorrent-rasterbar >= 1.0.6" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$libtorrent_PKG_ERRORS" >&5
as_fn_error $? "Package requirements (libtorrent-rasterbar >= 1.0.6) were not met:
$libtorrent_PKG_ERRORS
Consider adjusting the PKG_CONFIG_PATH environment variable if you
installed software in a non-standard prefix.
Alternatively, you may set the environment variables libtorrent_CFLAGS
and libtorrent_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details." "$LINENO" 5
elif test $pkg_failed = untried; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
path to pkg-config.
Alternatively, you may set the environment variables libtorrent_CFLAGS
and libtorrent_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.
To get pkg-config, see <http://pkg-config.freedesktop.org/>.
See \`config.log' for more details" "$LINENO" 5; }
else
libtorrent_CFLAGS=$pkg_cv_libtorrent_CFLAGS
libtorrent_LIBS=$pkg_cv_libtorrent_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
CPPFLAGS="$libtorrent_CFLAGS $CPPFLAGS"
LIBS="$libtorrent_LIBS $LIBS"
fi
pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for zlib" >&5
$as_echo_n "checking for zlib... " >&6; }
@@ -5808,8 +5681,11 @@ extract() {
return 1
fi
# BSD sed needs an actual newline character in the substitute command
new_line='
'
# Convert " -" to "\n" if not between quotes and remove possible leading white spaces
string=$(echo " $*" | $SED -e 's: -:\n: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

View File

@@ -12,23 +12,11 @@ AM_INIT_AUTOMAKE
# Define --wth-* and --enable-* arguments
AC_ARG_WITH(qt5,
[AS_HELP_STRING([--with-qt5],
[Compile using Qt5 (default=no)])],
AC_ARG_WITH(qt4,
[AS_HELP_STRING([--with-qt4],
[Compile using Qt4 (default=no)])],
[],
[with_qt5=no])
AC_ARG_WITH(libtorrent-rasterbar0.16,
[AS_HELP_STRING([--with-libtorrent-rasterbar0.16],
[Compile using libtorrent-rasterbar 0.16.x series (default=no)])],
[],
[with_libtorrent_rasterbar0_16=no])
AC_ARG_WITH(geoip-database-embedded,
[AS_HELP_STRING([--with-geoip-database-embedded],
[Embed the GeoIP database in the qBittorrent executable (please follow instructions in src/gui/geoip/README) (default=no)])],
[],
[with_geoip_database_embedded=no])
[with_qt4=no])
AC_ARG_WITH(qtsingleapplication,
[AS_HELP_STRING([--with-qtsingleapplication=@<:@system|shipped@:>@],
@@ -107,7 +95,6 @@ AS_CASE(["x$enable_gui"],
["xno"],
[AC_MSG_RESULT([no])
enable_qt_dbus=[no]
enable_geoip_database=[no]
QBT_ADD_CONFIG="$QBT_ADD_CONFIG nogui"],
[AC_MSG_RESULT([$enable_gui])
AC_MSG_ERROR([Unknown option "$enable_gui". Use either "yes" or "no".])])
@@ -134,16 +121,16 @@ AS_CASE(["x$enable_webui"],
[AC_MSG_RESULT([$enable_webui])
AC_MSG_ERROR([Unknown option "$enable_webui". Use either "yes" or "no".])])
AC_MSG_CHECKING([whether Qt5 should be enabled])
AS_CASE(["x$with_qt5"],
AC_MSG_CHECKING([whether Qt4 should be enabled])
AS_CASE(["x$with_qt4"],
["xno"],
[AC_MSG_RESULT([no])
FIND_QT4()],
FIND_QT5()],
["xyes"],
[AC_MSG_RESULT([yes])
FIND_QT5()],
[AC_MSG_RESULT([$with_qt5])
AC_MSG_ERROR([Unknown option "$with_qt5". Use either "yes" or "no".])])
FIND_QT4()],
[AC_MSG_RESULT([$with_qt4])
AC_MSG_ERROR([Unknown option "$with_qt4". Use either "yes" or "no".])])
AS_IF([test "x$QT_QMAKE" = "x"],
[AC_MSG_ERROR([Could not find qmake])
])
@@ -181,34 +168,6 @@ AS_IF([test "x$BOOST_SYSTEM_LIB" = "x"],
[AC_MSG_NOTICE([Boost.System LIB: $BOOST_SYSTEM_LIB])
LIBS="$BOOST_SYSTEM_LIB $LIBS"])
AC_MSG_CHECKING([whether to compile using libtorrent-rasterbar 0.16.x])
AS_CASE(["x$with_libtorrent_rasterbar0_16"],
["xno"],
[AC_MSG_RESULT([no])
PKG_CHECK_MODULES(libtorrent,
[libtorrent-rasterbar >= 1.0.6],
[CPPFLAGS="$libtorrent_CFLAGS $CPPFLAGS"
LIBS="$libtorrent_LIBS $LIBS"])],
["xyes"],
[AC_MSG_RESULT([yes])
PKG_CHECK_MODULES(libtorrent,
[libtorrent-rasterbar >= 0.16.19],
[CPPFLAGS="$libtorrent_CFLAGS $CPPFLAGS"
LIBS="$libtorrent_LIBS $LIBS"])],
[AC_MSG_RESULT([$with_libtorrent_rasterbar0_16])
AC_MSG_ERROR([Unknown option "$with_libtorrent_rasterbar0_16". Use either "yes" or "no".])])
AC_MSG_CHECKING([whether to embed the GeoIP database])
AS_CASE(["x$with_geoip_database_embedded"],
["xno"],
[AC_MSG_RESULT([no])
QBT_REMOVE_DEFINES="$QBT_REMOVE_DEFINES WITH_GEOIP_EMBEDDED"],
["xyes"],
[AC_MSG_RESULT([yes])
QBT_ADD_DEFINES="$QBT_ADD_DEFINES WITH_GEOIP_EMBEDDED"],
[AC_MSG_RESULT([$with_geoip_database_embedded])
AC_MSG_ERROR([Unknown option "$with_geoip_database_embedded". Use either "yes" or "no".])])
AC_MSG_CHECKING([which qtsingleapplication to use])
AS_CASE(["x$with_qtsingleapplication"],
["xshipped"],
@@ -220,7 +179,7 @@ AS_CASE(["x$with_qtsingleapplication"],
[AC_MSG_RESULT([$with_qtsingleapplication])
AC_MSG_ERROR([Unknown option "$with_qtsingleapplication". Use either "system" or "shipped".])])
AS_IF([test "x$with_qt5" = "xno"],
AS_IF([test "x$with_qt4" = "xyes"],
[AC_MSG_CHECKING([which qjson to use])
AS_CASE(["x$with_qjson"],
["xshipped"],
@@ -237,6 +196,11 @@ AS_IF([test "x$with_qt5" = "xno"],
AC_MSG_ERROR([Unknown option "$with_qjson". Use either "system" or "shipped".])])
])
PKG_CHECK_MODULES(libtorrent,
[libtorrent-rasterbar >= 1.0.6],
[CPPFLAGS="$libtorrent_CFLAGS $CPPFLAGS"
LIBS="$libtorrent_LIBS $LIBS"])
PKG_CHECK_MODULES(zlib,
[zlib],
[CPPFLAGS="$zlib_CFLAGS $CPPFLAGS"
@@ -258,8 +222,11 @@ extract() {
return 1
fi
# BSD sed needs an actual newline character in the substitute command
new_line='
'
# Convert " -" to "\n" if not between quotes and remove possible leading white spaces
string=$(echo " $*" | $SED -e 's: -:\n: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

2
dist/mac/Info.plist vendored
View File

@@ -45,7 +45,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>3.2.2</string>
<string>3.3.0</string>
<key>CFBundleSignature</key>
<string>qBit</string>
<key>CFBundleExecutable</key>

View File

@@ -11,7 +11,7 @@ TRANSLATORS:
5. Save the files with utf8 encoding and BOM.
6. Submit your changes: 1) as a pull request to the official git repo or
2) open an issue to the bugtracker and attach them or 3) via email or
4)the same way you provide the tranlations for qbt itself
4)the same way you provide the translations for qbt itself
PACKAGERS:

View File

@@ -1,9 +1,9 @@
;Installer strings
;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_GERMAN} "qBittorrent (erforderlich)"
;LangString inst_dekstop ${LANG_ENGLISH} "Create Desktop Shortcut"
LangString inst_dekstop ${LANG_GERMAN} "Verknüpfung am Desktop erstellen"
LangString inst_dekstop ${LANG_GERMAN} "Verknüpfung auf dem Desktop erstellen"
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
LangString inst_startmenu ${LANG_GERMAN} "Eintrag im Startmenü erstellen"
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
@@ -38,12 +38,12 @@ LangString remove_conf ${LANG_GERMAN} "Einstellungsdateien entfernen"
;LangString remove_firewall ${LANG_ENGLISH} "Remove Windows Firewall rule"
LangString remove_firewall ${LANG_GERMAN} "Regel in der Windows Firewall entfernen"
;LangString remove_firewallinfo ${LANG_ENGLISH} "Removing Windows Firewall rule"
LangString remove_firewallinfo ${LANG_GERMAN} "Entferne Regel in der Windows Firewall"
LangString remove_firewallinfo ${LANG_GERMAN} "Entferne Regel aus der Windows Firewall"
;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data"
LangString remove_cache ${LANG_GERMAN} "Torrents und zwischengespeicherte Daten entfernen"
;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling."
LangString uninst_warning ${LANG_GERMAN} "qBittorrent läuft gerade. Bitte das Programm vor der Deinstallation beenden."
;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:"
LangString uninst_tor_warn ${LANG_GERMAN} "Dateiverknüfung mit .torrent-Dateien konnte nicht entfernt werden, da dieser Typ mit diesem Programm verknüpft ist:"
LangString uninst_tor_warn ${LANG_GERMAN} "Dateiverknüpfung mit .torrent-Dateien konnte nicht entfernt werden, da dieser Typ mit diesem Programm verknüpft ist:"
;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:"
LangString uninst_mag_warn ${LANG_GERMAN} "Dateiverknüfung mit Magnet-Links konnte nicht entfernt werden, da dieser Typ mit diesem Programm verknüpft ist:"
LangString uninst_mag_warn ${LANG_GERMAN} "Dateiverknüpfung mit Magnet-Links konnte nicht entfernt werden, da dieser Typ mit diesem Programm verknüpft ist:"

View File

@@ -19,7 +19,7 @@ XPStyle on
!define CSIDL_APPDATA '0x1A' ;Application Data path
!define CSIDL_LOCALAPPDATA '0x1C' ;Local Application Data path
!define PROG_VERSION "3.2.2"
!define PROG_VERSION "3.3.0"
!define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun
!define MUI_FINISHPAGE_RUN_TEXT $(launch_qbt)

View File

@@ -111,7 +111,7 @@ To install QBittorrent, do the following:
=============
Please create bugreports at http://svn.netlabs.org/qtapps
Only bug reports with a reproducable bug are accepted. :-)
Only bug reports with a reproducible bug are accepted. :-)
5. CREDITS

View File

@@ -33,7 +33,7 @@
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 23
#serial 26
AC_DEFUN([AX_BOOST_BASE],
[
@@ -92,8 +92,11 @@ if test "x$want_boost" = "xyes"; then
libsubdirs="lib"
ax_arch=`uname -m`
case $ax_arch in
x86_64|ppc64|s390x|sparc64|aarch64)
libsubdirs="lib64 lib lib64"
x86_64)
libsubdirs="lib64 libx32 lib lib64"
;;
ppc64|s390x|sparc64|aarch64|ppc64le)
libsubdirs="lib64 lib lib64 ppc64le"
;;
esac
@@ -170,6 +173,10 @@ if test "x$want_boost" = "xyes"; then
dnl if we found no boost with system layout we search for boost libraries
dnl built and installed without the --layout=system option or for a staged(not installed) version
if test "x$succeeded" != "xyes"; then
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
BOOST_CPPFLAGS=
BOOST_LDFLAGS=
_version=0
if test "$ac_boost_path" != ""; then
if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
@@ -182,6 +189,12 @@ if test "x$want_boost" = "xyes"; then
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE"
done
dnl if nothing found search for layout used in Windows distributions
if test -z "$BOOST_CPPFLAGS"; then
if test -d "$ac_boost_path/boost" && test -r "$ac_boost_path/boost"; then
BOOST_CPPFLAGS="-I$ac_boost_path"
fi
fi
fi
else
if test "$cross_compiling" != yes; then

View File

@@ -54,7 +54,7 @@ AS_IF([test "x$QT_QMAKE" != "x"],
# Sets the HAVE_QTDBUS variable to true or false.
# --------------------------------------
AC_DEFUN([FIND_QTDBUS],
[AS_IF([test "x$with_qt5" = "xyes"],
[AS_IF([test "x$with_qt4" = "xno"],
[AC_MSG_CHECKING([for Qt5DBus >= 5.2.0])
PKG_CHECK_EXISTS([Qt5DBus >= 5.2.0],
[AC_MSG_RESULT([found])

View File

@@ -10,7 +10,9 @@ exists($$OUT_PWD/../conf.pri) {
}
LIBS += -framework Carbon -framework IOKit
CONFIG += c++11
# C++11 support
lessThan(QT_MAJOR_VERSION, 5): QMAKE_CXXFLAGS += -std=c++11
QT_LANG_PATH = ../dist/qt-translations
DIST_PATH = ../dist/mac
@@ -56,6 +58,3 @@ QMAKE_BUNDLE_DATA += qt_translations
ICON = $$DIST_PATH/qbittorrent_mac.icns
QMAKE_INFO_PLIST = $$DIST_PATH/Info.plist
DEFINES += WITH_GEOIP_EMBEDDED
message("On Mac OS X, GeoIP database must be embedded.")

View File

@@ -1,3 +1,6 @@
# C++11 support
lessThan(QT_MAJOR_VERSION, 5): QMAKE_CXXFLAGS += -std=c++11
exists(conf.pri) {
# to the conf.pri goes all system dependent stuff
include(conf.pri)
@@ -13,8 +16,4 @@ LIBS += \
RC_FILE = qbittorrent_os2.rc
# LIBTORRENT DEFINES
DEFINES += WITH_SHIPPED_GEOIP_H
DEFINES += BOOST_ASIO_DYN_LINK
DEFINES += WITH_GEOIP_EMBEDDED
message("On eCS(OS/2), GeoIP database must be embedded.")

View File

@@ -27,3 +27,6 @@ strace_win {
}
SOURCES += $$PWD/main.cpp
# upgrade code
HEADERS += $$PWD/upgrade.h

View File

@@ -32,8 +32,10 @@
#include <QLocale>
#include <QLibraryInfo>
#include <QSysInfo>
#include <QProcess>
#ifndef DISABLE_GUI
#include "gui/guiiconprovider.h"
#ifdef Q_OS_WIN
#include <Windows.h>
#include <QSharedMemory>
@@ -46,26 +48,40 @@
#endif // Q_OS_MAC
#include "mainwindow.h"
#include "addnewtorrentdialog.h"
#include "shutdownconfirm.h"
#else // DISABLE_GUI
#include <iostream>
#endif // DISABLE_GUI
#ifndef DISABLE_WEBUI
#include "../webui/webui.h"
#include "webui/webui.h"
#endif
#include "application.h"
#include "logger.h"
#include "preferences.h"
#include "qbtsession.h"
#include "torrentpersistentdata.h"
#include "core/logger.h"
#include "core/preferences.h"
#include "core/utils/fs.h"
#include "core/utils/misc.h"
#include "core/iconprovider.h"
#include "core/scanfoldersmodel.h"
#include "core/net/smtp.h"
#include "core/net/downloadmanager.h"
#include "core/net/geoipmanager.h"
#include "core/bittorrent/session.h"
#include "core/bittorrent/torrenthandle.h"
static const char PARAMS_SEPARATOR[] = "|";
Application::Application(const QString &id, int &argc, char **argv)
: BaseApplication(id, argc, argv)
, m_running(false)
#ifndef DISABLE_GUI
, m_shutdownAct(ShutdownAction::None)
#endif
{
Logger::initInstance();
Preferences::initInstance();
#if defined(Q_OS_MACX) && !defined(DISABLE_GUI)
if (QSysInfo::MacintoshVersion > QSysInfo::MV_10_8) {
// fix Mac OS X 10.9 (mavericks) font issue
@@ -85,6 +101,8 @@ Application::Application(const QString &id, int &argc, char **argv)
connect(this, SIGNAL(messageReceived(const QString &)), SLOT(processMessage(const QString &)));
connect(this, SIGNAL(aboutToQuit()), SLOT(cleanup()));
Logger::instance()->addMessage(tr("qBittorrent %1 started", "qBittorrent v3.2.0alpha started").arg(VERSION));
}
void Application::processMessage(const QString &message)
@@ -98,6 +116,94 @@ void Application::processMessage(const QString &message)
m_paramsQueue.append(params);
}
void Application::sendNotificationEmail(BitTorrent::TorrentHandle *const torrent)
{
// Prepare mail content
QString content = QObject::tr("Torrent name: %1").arg(torrent->name()) + "\n";
content += QObject::tr("Torrent size: %1").arg(Utils::Misc::friendlyUnit(torrent->wantedSize())) + "\n";
content += QObject::tr("Save path: %1").arg(torrent->savePath()) + "\n\n";
content += QObject::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";
content += QObject::tr("Thank you for using qBittorrent.") + "\n";
// Send the notification email
Net::Smtp *sender = new Net::Smtp;
sender->sendMail("notification@qbittorrent.org",
Preferences::instance()->getMailNotificationEmail(),
QObject::tr("[qBittorrent] '%1' has finished downloading").arg(torrent->name()),
content);
}
void Application::torrentFinished(BitTorrent::TorrentHandle *const torrent)
{
Preferences *const pref = Preferences::instance();
// AutoRun program
if (pref->isAutoRunEnabled()) {
QString program = pref->getAutoRunProgram();
program.replace("%N", torrent->name());
program.replace("%L", torrent->label());
program.replace("%F", Utils::Fs::toNativePath(torrent->contentPath()));
program.replace("%R", Utils::Fs::toNativePath(torrent->rootPath()));
program.replace("%D", Utils::Fs::toNativePath(torrent->savePath()));
program.replace("%C", QString::number(torrent->filesCount()));
program.replace("%Z", QString::number(torrent->totalSize()));
program.replace("%T", torrent->currentTracker());
program.replace("%I", torrent->hash());
QProcess::startDetached(program);
}
// Mail notification
if (pref->isMailNotificationEnabled())
sendNotificationEmail(torrent);
}
void Application::allTorrentsFinished()
{
#ifndef DISABLE_GUI
Preferences *const pref = Preferences::instance();
bool will_shutdown = (pref->shutdownWhenDownloadsComplete()
|| pref->shutdownqBTWhenDownloadsComplete()
|| pref->suspendWhenDownloadsComplete()
|| pref->hibernateWhenDownloadsComplete());
// Auto-Shutdown
if (will_shutdown) {
bool suspend = pref->suspendWhenDownloadsComplete();
bool hibernate = pref->hibernateWhenDownloadsComplete();
bool shutdown = pref->shutdownWhenDownloadsComplete();
// Confirm shutdown
ShutdownAction action = ShutdownAction::None;
if (suspend)
action = ShutdownAction::Suspend;
else if (hibernate)
action = ShutdownAction::Hibernate;
else if (shutdown)
action = ShutdownAction::Shutdown;
if (!ShutdownConfirmDlg::askForConfirmation(action)) return;
// Actually shut down
if (suspend || hibernate || shutdown) {
qDebug("Preparing for auto-shutdown because all downloads are complete!");
// Disabling it for next time
pref->setShutdownWhenDownloadsComplete(false);
pref->setSuspendWhenDownloadsComplete(false);
pref->setHibernateWhenDownloadsComplete(false);
// Make sure preferences are synced before exiting
m_shutdownAct = action;
}
qDebug("Exiting the application");
exit();
}
#endif // DISABLE_GUI
}
bool Application::sendParams(const QStringList &params)
{
return sendMessage(params.join(QLatin1String(PARAMS_SEPARATOR)));
@@ -114,45 +220,36 @@ void Application::processParams(const QStringList &params)
m_window->activate(); // show UI
return;
}
const bool useTorrentAdditionDialog = Preferences::instance()->useAdditionDialog();
#endif
foreach (QString param, params) {
param = param.trimmed();
if (misc::isUrl(param)) {
QBtSession::instance()->downloadFromUrl(param);
}
else {
if (param.startsWith("bc://bt/", Qt::CaseInsensitive)) {
qDebug("Converting bc link to magnet link");
param = misc::bcLinkToMagnet(param);
}
if (param.startsWith("magnet:", Qt::CaseInsensitive)) {
#ifndef DISABLE_GUI
if (useTorrentAdditionDialog)
AddNewTorrentDialog::showMagnet(param, m_window);
else
if (Preferences::instance()->useAdditionDialog())
AddNewTorrentDialog::show(param, m_window);
else
#endif
QBtSession::instance()->addMagnetUri(param);
}
else {
#ifndef DISABLE_GUI
if (useTorrentAdditionDialog)
AddNewTorrentDialog::showTorrent(param, QString(), m_window);
else
#endif
QBtSession::instance()->addTorrent(param);
}
}
BitTorrent::Session::instance()->addTorrent(param);
}
}
int Application::exec(const QStringList &params)
{
// Resume unfinished torrents
QBtSession::instance()->startUpTorrents();
Net::DownloadManager::initInstance();
#ifdef DISABLE_GUI
IconProvider::initInstance();
#else
GuiIconProvider::initInstance();
#endif
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()));
#ifndef DISABLE_COUNTRIES_RESOLUTION
Net::GeoIPManager::initInstance();
#endif
ScanFoldersModel::initInstance(this);
#ifndef DISABLE_WEBUI
m_webui = new WebUI;
@@ -294,6 +391,8 @@ void Application::initializeTranslation()
#if (!defined(DISABLE_GUI) && defined(Q_OS_WIN))
void Application::shutdownCleanup(QSessionManager &manager)
{
Q_UNUSED(manager);
// This is only needed for a special case on Windows XP.
// (but is called for every Windows version)
// If a process takes too much time to exit during OS
@@ -357,10 +456,16 @@ void Application::cleanup()
#ifndef DISABLE_WEBUI
delete m_webui;
#endif
QBtSession::drop();
TorrentPersistentData::drop();
Preferences::drop();
Logger::drop();
ScanFoldersModel::freeInstance();
BitTorrent::Session::freeInstance();
#ifndef DISABLE_COUNTRIES_RESOLUTION
Net::GeoIPManager::freeInstance();
#endif
Preferences::freeInstance();
Logger::freeInstance();
IconProvider::freeInstance();
Net::DownloadManager::freeInstance();
#ifndef DISABLE_GUI
#ifdef Q_OS_WIN
typedef BOOL (WINAPI *PSHUTDOWNBRDESTROY)(HWND);
@@ -370,6 +475,9 @@ void Application::cleanup()
shutdownBRDestroy((HWND)m_window->effectiveWinId());
#endif // Q_OS_WIN
delete m_window;
if (m_shutdownAct != ShutdownAction::None) {
qDebug() << "Sending computer shutdown/suspend/hibernate signal...";
Utils::Misc::shutdownComputer(m_shutdownAct);
}
#endif
}

View File

@@ -50,10 +50,17 @@ QT_END_NAMESPACE
typedef QtSingleCoreApplication BaseApplication;
#endif
#include "core/utils/misc.h"
#ifndef DISABLE_WEBUI
class WebUI;
#endif
namespace BitTorrent
{
class TorrentHandle;
}
class Application : public BaseApplication
{
Q_OBJECT
@@ -77,6 +84,8 @@ protected:
private slots:
void processMessage(const QString &message);
void torrentFinished(BitTorrent::TorrentHandle *const torrent);
void allTorrentsFinished();
void cleanup();
#if (!defined(DISABLE_GUI) && defined(Q_OS_WIN))
void shutdownCleanup(QSessionManager &manager);
@@ -87,6 +96,7 @@ private:
#ifndef DISABLE_GUI
QPointer<MainWindow> m_window;
ShutdownAction m_shutdownAct;
#endif
#ifndef DISABLE_WEBUI
@@ -99,6 +109,7 @@ private:
void initializeTranslation();
void processParams(const QStringList &params);
void sendNotificationEmail(BitTorrent::TorrentHandle *const torrent);
};
#endif // APPLICATION_H

View File

@@ -33,6 +33,7 @@
#include <QScopedPointer>
#ifndef DISABLE_GUI
// GUI-only includes
#include <QFont>
#include <QMessageBox>
#include <QPainter>
@@ -47,8 +48,13 @@ Q_IMPORT_PLUGIN(QICOPlugin)
Q_IMPORT_PLUGIN(qico)
#endif
#endif // QBT_STATIC_QT
#else // DISABLE_GUI
#else
// NoGUI-only includes
#include <cstdio>
#ifdef Q_OS_UNIX
#include "unistd.h"
#endif
#endif // DISABLE_GUI
#ifdef Q_OS_UNIX
@@ -66,9 +72,10 @@ Q_IMPORT_PLUGIN(qico)
#include <cstdlib>
#include <iostream>
#include "application.h"
#include "misc.h"
#include "preferences.h"
#include "logger.h"
#include "core/utils/misc.h"
#include "core/preferences.h"
#include "upgrade.h"
// Signal handlers
#if defined(Q_OS_UNIX) || defined(STACKTRACE_WIN)
@@ -120,13 +127,11 @@ QBtCommandLineParameters parseCommandLine();
// Main
int main(int argc, char *argv[])
{
//Initialize logger singleton here to avoid threading issues
Logger::instance()->addMessage(QObject::tr("qBittorrent %1 started", "qBittorrent v3.2.0alpha started").arg(VERSION));
// We must save it here because QApplication constructor may change it
bool isOneArg = (argc == 2);
// Create Application
QString appId = QLatin1String("qBittorrent-") + misc::getUserIDString();
QString appId = QLatin1String("qBittorrent-") + Utils::Misc::getUserIDString();
QScopedPointer<Application> app(new Application(appId, argc, argv));
const QBtCommandLineParameters params = parseCommandLine();
@@ -176,8 +181,16 @@ int main(int argc, char *argv[])
if (!qputenv("QBITTORRENT", QByteArray(VERSION)))
std::cerr << "Couldn't set environment variable...\n";
#ifndef DISABLE_GUI
if (!userAgreesWithLegalNotice())
return EXIT_SUCCESS;
#else
if (!params.shouldDaemonize
&& isatty(fileno(stdin))
&& isatty(fileno(stdout))
&& !userAgreesWithLegalNotice())
return EXIT_SUCCESS;
#endif
// Check if qBittorrent is already running for this user
if (app->isRunning()) {
@@ -191,12 +204,20 @@ int main(int argc, char *argv[])
#endif
qDebug("qBittorrent is already running for this user.");
misc::msleep(300);
Utils::Misc::msleep(300);
app->sendParams(params.torrents);
return EXIT_SUCCESS;
}
#ifndef DISABLE_GUI
if (!upgrade()) return EXIT_FAILURE;
#else
if (!upgrade(!params.shouldDaemonize
&& isatty(fileno(stdin))
&& isatty(fileno(stdout)))) return EXIT_FAILURE;
#endif
srand(time(0));
#ifdef DISABLE_GUI
if (params.shouldDaemonize) {
@@ -398,7 +419,7 @@ void displayUsage(const QString& prg_name)
#else
QMessageBox msgBox(QMessageBox::Information, QObject::tr("Help"), makeUsage(prg_name), QMessageBox::Ok);
msgBox.show(); // Need to be shown or to moveToCenter does not work
msgBox.move(misc::screenCenter(&msgBox));
msgBox.move(Utils::Misc::screenCenter(&msgBox));
msgBox.exec();
#endif
}
@@ -410,7 +431,7 @@ void displayBadArgMessage(const QString& message)
QMessageBox msgBox(QMessageBox::Critical, QObject::tr("Bad command line"),
message + QLatin1Char('\n') + help, QMessageBox::Ok);
msgBox.show(); // Need to be shown or to moveToCenter does not work
msgBox.move(misc::screenCenter(&msgBox));
msgBox.move(Utils::Misc::screenCenter(&msgBox));
msgBox.exec();
#else
std::cerr << qPrintable(QObject::tr("Bad command line: "));
@@ -442,7 +463,7 @@ bool userAgreesWithLegalNotice()
msgBox.addButton(QObject::tr("Cancel"), QMessageBox::RejectRole);
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(misc::screenCenter(&msgBox));
msgBox.move(Utils::Misc::screenCenter(&msgBox));
msgBox.exec();
if (msgBox.clickedButton() == agree_button) {
// Save the answer

132
src/app/upgrade.h Normal file
View File

@@ -0,0 +1,132 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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 UPGRADE_H
#define UPGRADE_H
#include <libtorrent/lazy_entry.hpp>
#include <libtorrent/entry.hpp>
#include <libtorrent/bencode.hpp>
#include <QString>
#include <QDir>
#include <QFile>
#ifndef DISABLE_GUI
#include <QMessageBox>
#endif
#include "core/logger.h"
#include "core/utils/fs.h"
#include "core/utils/misc.h"
bool userAcceptsUpgrade()
{
#ifdef DISABLE_GUI
std::cout << std::endl << "*** " << qPrintable(QObject::tr("Upgrade")) << " ***" << std::endl;
char ret = '\0';
do {
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'));
if ((ret == 'y') || (ret == 'Y'))
return true;
#else
QMessageBox msgBox;
msgBox.setText(QObject::tr("You updated from an older version that saved things differently. You must migrate to the new saving system. If you continue, you will not be able to use an older version than v3.3.0 again."));
msgBox.setWindowTitle(QObject::tr("Upgrade"));
msgBox.addButton(QMessageBox::Abort);
msgBox.addButton(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Abort);
msgBox.show(); // Need to be shown or to moveToCenter does not work
msgBox.move(Utils::Misc::screenCenter(&msgBox));
if (msgBox.exec() == QMessageBox::Ok)
return true;
#endif
return false;
}
bool upgradeResumeFile(const QString &filepath)
{
QFile file1(filepath);
if (!file1.open(QIODevice::ReadOnly))
return false;
QByteArray data = file1.readAll();
file1.close();
libtorrent::lazy_entry fastOld;
libtorrent::error_code ec;
libtorrent::lazy_bdecode(data.constData(), data.constData() + data.size(), fastOld, ec);
if ((fastOld.type() != libtorrent::lazy_entry::dict_t) && !ec) return false;
libtorrent::entry fastNew;
fastNew = fastOld;
int priority = fastOld.dict_find_int_value("qBt-queuePosition");
QFile file2(QString("%1.%2").arg(filepath).arg(priority > 0 ? priority : 0));
QVector<char> out;
libtorrent::bencode(std::back_inserter(out), fastNew);
if (file2.open(QIODevice::WriteOnly)) {
if (file2.write(&out[0], out.size()) == out.size()) {
Utils::Fs::forceRemove(filepath);
return true;
}
}
return false;
}
bool upgrade(bool ask = true)
{
QString backupFolderPath = Utils::Fs::expandPathAbs(Utils::Fs::QDesktopServicesDataLocation() + "BT_backup");
QDir backupFolderDir(backupFolderPath);
if (!backupFolderDir.exists()) return true;
QStringList backupFiles = backupFolderDir.entryList(QStringList() << QLatin1String("*.fastresume"), QDir::Files, QDir::Unsorted);
if (!backupFiles.isEmpty()) {
if (ask && !userAcceptsUpgrade()) return false;
QRegExp rx(QLatin1String("^([A-Fa-f0-9]{40})\\.fastresume$"));
foreach (QString backupFile, backupFiles) {
if (rx.indexIn(backupFile) != -1) {
if (!upgradeResumeFile(backupFolderDir.absoluteFilePath(backupFile)))
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);
}
}
}
return true;
}
#endif // UPGRADE_H

View File

@@ -0,0 +1,64 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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 "cachestatus.h"
using namespace BitTorrent;
CacheStatus::CacheStatus(const libtorrent::cache_status &nativeStatus)
: m_nativeStatus(nativeStatus)
{
}
int CacheStatus::totalUsedBuffers() const
{
return m_nativeStatus.total_used_buffers;
}
qreal CacheStatus::readRatio() const
{
if (m_nativeStatus.blocks_read > 0)
return (static_cast<qreal>(m_nativeStatus.blocks_read_hit) / m_nativeStatus.blocks_read);
else
return -1;
}
int CacheStatus::jobQueueLength() const
{
return m_nativeStatus.job_queue_length;
}
int CacheStatus::averageJobTime() const
{
return m_nativeStatus.average_job_time;
}
qlonglong CacheStatus::queuedBytes() const
{
return m_nativeStatus.queued_bytes;
}

View File

@@ -0,0 +1,53 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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 BITTORRENT_CACHESTATUS_H
#define BITTORRENT_CACHESTATUS_H
#include <libtorrent/disk_io_thread.hpp>
#include <QtGlobal>
namespace BitTorrent
{
class CacheStatus
{
public:
CacheStatus(const libtorrent::cache_status &nativeStatus);
int totalUsedBuffers() const;
qreal readRatio() const;
int jobQueueLength() const;
int averageJobTime() const;
qlonglong queuedBytes() const;
private:
libtorrent::cache_status m_nativeStatus;
};
}
#endif // BITTORRENT_CACHESTATUS_H

View File

@@ -0,0 +1,98 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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 <QHash>
#include "infohash.h"
using namespace BitTorrent;
InfoHash::InfoHash()
: m_valid(false)
{
}
InfoHash::InfoHash(const libtorrent::sha1_hash &nativeHash)
: m_valid(true)
, m_nativeHash(nativeHash)
{
char out[(libtorrent::sha1_hash::size * 2) + 1];
libtorrent::to_hex((char const*)&m_nativeHash[0], libtorrent::sha1_hash::size, out);
m_hashString = QString(out);
}
InfoHash::InfoHash(const QString &hashString)
: m_valid(false)
, m_hashString(hashString)
{
QByteArray raw = m_hashString.toLatin1();
if (raw.size() == 40)
m_valid = libtorrent::from_hex(raw.constData(), 40, (char*)&m_nativeHash[0]);
}
InfoHash::InfoHash(const InfoHash &other)
: m_valid(other.m_valid)
, m_nativeHash(other.m_nativeHash)
, m_hashString(other.m_hashString)
{
}
bool InfoHash::isValid() const
{
return m_valid;
}
InfoHash::operator libtorrent::sha1_hash() const
{
return m_nativeHash;
}
InfoHash::operator QString() const
{
return m_hashString;
}
bool InfoHash::operator==(const InfoHash &other) const
{
return (m_nativeHash == other.m_nativeHash);
}
bool InfoHash::operator!=(const InfoHash &other) const
{
return (m_nativeHash != other.m_nativeHash);
}
uint qHash(const InfoHash &key, uint seed)
{
return qHash(static_cast<QString>(key), seed);
}

View File

@@ -0,0 +1,61 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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 BITTORRENT_INFOHASH_H
#define BITTORRENT_INFOHASH_H
#include <libtorrent/sha1_hash.hpp>
#include <QString>
namespace BitTorrent
{
class InfoHash
{
public:
InfoHash();
InfoHash(const libtorrent::sha1_hash &nativeHash);
InfoHash(const QString &hashString);
InfoHash(const InfoHash &other);
bool isValid() const;
operator libtorrent::sha1_hash() const;
operator QString() const;
bool operator==(const InfoHash &other) const;
bool operator!=(const InfoHash &other) const;
private:
bool m_valid;
libtorrent::sha1_hash m_nativeHash;
QString m_hashString;
};
}
uint qHash(const BitTorrent::InfoHash &key, uint seed);
#endif // BITTORRENT_INFOHASH_H

View File

@@ -0,0 +1,93 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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 <libtorrent/bencode.hpp>
#include <libtorrent/error_code.hpp>
#include <libtorrent/magnet_uri.hpp>
#include "core/utils/string.h"
#include "magneturi.h"
namespace libt = libtorrent;
using namespace BitTorrent;
MagnetUri::MagnetUri(const QString &url)
: m_valid(false)
, m_url(url)
{
if (url.isEmpty()) return;
libt::error_code ec;
libt::parse_magnet_uri(url.toUtf8().constData(), m_addTorrentParams, ec);
if (ec) return;
m_valid = true;
m_hash = m_addTorrentParams.info_hash;
m_name = Utils::String::fromStdString(m_addTorrentParams.name);
foreach (const std::string &tracker, m_addTorrentParams.trackers)
m_trackers.append(Utils::String::fromStdString(tracker));
foreach (const std::string &urlSeed, m_addTorrentParams.url_seeds)
m_urlSeeds.append(QUrl(urlSeed.c_str()));
}
bool MagnetUri::isValid() const
{
return m_valid;
}
InfoHash MagnetUri::hash() const
{
return m_hash;
}
QString MagnetUri::name() const
{
return m_name;
}
QList<TrackerEntry> MagnetUri::trackers() const
{
return m_trackers;
}
QList<QUrl> MagnetUri::urlSeeds() const
{
return m_urlSeeds;
}
QString MagnetUri::url() const
{
return m_url;
}
libtorrent::add_torrent_params MagnetUri::addTorrentParams() const
{
return m_addTorrentParams;
}

View File

@@ -0,0 +1,68 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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 BITTORRENT_MAGNETURI_H
#define BITTORRENT_MAGNETURI_H
#include <QString>
#include <QList>
#include <QUrl>
#include <libtorrent/add_torrent_params.hpp>
#include "infohash.h"
#include "trackerentry.h"
namespace BitTorrent
{
class MagnetUri
{
public:
explicit MagnetUri(const QString &url = QString());
bool isValid() const;
InfoHash hash() const;
QString name() const;
QList<TrackerEntry> trackers() const;
QList<QUrl> urlSeeds() const;
QString url() const;
libtorrent::add_torrent_params addTorrentParams() const;
private:
bool m_valid;
QString m_url;
InfoHash m_hash;
QString m_name;
QList<TrackerEntry> m_trackers;
QList<QUrl> m_urlSeeds;
libtorrent::add_torrent_params m_addTorrentParams;
};
}
#endif // BITTORRENT_MAGNETURI_H

View File

@@ -0,0 +1,255 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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 "core/net/geoipmanager.h"
#include "core/utils/string.h"
#include "core/unicodestrings.h"
#include "peerinfo.h"
namespace libt = libtorrent;
using namespace BitTorrent;
// PeerAddress
PeerAddress::PeerAddress()
: port(0)
{
}
PeerAddress::PeerAddress(QHostAddress ip, ushort port)
: ip(ip)
, port(port)
{
}
// PeerInfo
PeerInfo::PeerInfo(const libt::peer_info &nativeInfo)
: m_nativeInfo(nativeInfo)
{
}
bool PeerInfo::fromDHT() const
{
return (m_nativeInfo.source & libt::peer_info::dht);
}
bool PeerInfo::fromPeX() const
{
return (m_nativeInfo.source & libt::peer_info::pex);
}
bool PeerInfo::fromLSD() const
{
return (m_nativeInfo.source & libt::peer_info::lsd);
}
#ifndef DISABLE_COUNTRIES_RESOLUTION
QString PeerInfo::country() const
{
return Net::GeoIPManager::instance()->lookup(address().ip);
}
#endif
bool PeerInfo::isInteresting() const
{
return (m_nativeInfo.flags & libt::peer_info::interesting);
}
bool PeerInfo::isChocked() const
{
return (m_nativeInfo.flags & libt::peer_info::choked);
}
bool PeerInfo::isRemoteInterested() const
{
return (m_nativeInfo.flags & libt::peer_info::remote_interested);
}
bool PeerInfo::isRemoteChocked() const
{
return (m_nativeInfo.flags & libt::peer_info::remote_choked);
}
bool PeerInfo::isSupportsExtensions() const
{
return (m_nativeInfo.flags & libt::peer_info::supports_extensions);
}
bool PeerInfo::isLocalConnection() const
{
return (m_nativeInfo.flags & libt::peer_info::local_connection);
}
bool PeerInfo::isHandshake() const
{
return (m_nativeInfo.flags & libt::peer_info::handshake);
}
bool PeerInfo::isConnecting() const
{
return (m_nativeInfo.flags & libt::peer_info::connecting);
}
bool PeerInfo::isQueued() const
{
return (m_nativeInfo.flags & libt::peer_info::queued);
}
bool PeerInfo::isOnParole() const
{
return (m_nativeInfo.flags & libt::peer_info::on_parole);
}
bool PeerInfo::isSeed() const
{
return (m_nativeInfo.flags & libt::peer_info::seed);
}
bool PeerInfo::optimisticUnchoke() const
{
return (m_nativeInfo.flags & libt::peer_info::optimistic_unchoke);
}
bool PeerInfo::isSnubbed() const
{
return (m_nativeInfo.flags & libt::peer_info::snubbed);
}
bool PeerInfo::isUploadOnly() const
{
return (m_nativeInfo.flags & libt::peer_info::upload_only);
}
bool PeerInfo::isEndgameMode() const
{
return (m_nativeInfo.flags & libt::peer_info::endgame_mode);
}
bool PeerInfo::isHolepunched() const
{
return (m_nativeInfo.flags & libt::peer_info::holepunched);
}
bool PeerInfo::useI2PSocket() const
{
return (m_nativeInfo.flags & libt::peer_info::i2p_socket);
}
bool PeerInfo::useUTPSocket() const
{
return (m_nativeInfo.flags & libt::peer_info::utp_socket);
}
bool PeerInfo::useSSLSocket() const
{
return (m_nativeInfo.flags & libt::peer_info::ssl_socket);
}
bool PeerInfo::isRC4Encrypted() const
{
return (m_nativeInfo.flags & libt::peer_info::rc4_encrypted);
}
bool PeerInfo::isPlaintextEncrypted() const
{
return (m_nativeInfo.flags & libt::peer_info::plaintext_encrypted);
}
PeerAddress PeerInfo::address() const
{
return PeerAddress(QHostAddress(QString::fromStdString(m_nativeInfo.ip.address().to_string())),
m_nativeInfo.ip.port());
}
QString PeerInfo::client() const
{
return Utils::String::fromStdString(m_nativeInfo.client);
}
qreal PeerInfo::progress() const
{
return m_nativeInfo.progress;
}
int PeerInfo::payloadUpSpeed() const
{
return m_nativeInfo.payload_up_speed;
}
int PeerInfo::payloadDownSpeed() const
{
return m_nativeInfo.payload_down_speed;
}
qlonglong PeerInfo::totalUpload() const
{
return m_nativeInfo.total_upload;
}
qlonglong PeerInfo::totalDownload() const
{
return m_nativeInfo.total_download;
}
QBitArray PeerInfo::pieces() const
{
QBitArray result(m_nativeInfo.pieces.size());
for (int i = 0; i < m_nativeInfo.pieces.size(); ++i)
result.setBit(i, m_nativeInfo.pieces.get_bit(i));
return result;
}
QString PeerInfo::connectionType() const
{
if (m_nativeInfo.flags & libt::peer_info::utp_socket)
return QString::fromUtf8(C_UTP);
QString connection;
switch(m_nativeInfo.connection_type) {
case libt::peer_info::http_seed:
case libt::peer_info::web_seed:
connection = "Web";
break;
default:
connection = "BT";
}
return connection;
}

View File

@@ -0,0 +1,101 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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 BITTORRENT_PEERINFO_H
#define BITTORRENT_PEERINFO_H
#include <libtorrent/peer_info.hpp>
#include <QHostAddress>
#include <QBitArray>
namespace BitTorrent
{
struct PeerAddress
{
QHostAddress ip;
ushort port;
PeerAddress();
PeerAddress(QHostAddress ip, ushort port);
};
class PeerInfo
{
public:
PeerInfo(const libtorrent::peer_info &nativeInfo);
bool fromDHT() const;
bool fromPeX() const;
bool fromLSD() const;
bool isInteresting() const;
bool isChocked() const;
bool isRemoteInterested() const;
bool isRemoteChocked() const;
bool isSupportsExtensions() const;
bool isLocalConnection() const;
bool isHandshake() const;
bool isConnecting() const;
bool isQueued() const;
bool isOnParole() const;
bool isSeed() const;
bool optimisticUnchoke() const;
bool isSnubbed() const;
bool isUploadOnly() const;
bool isEndgameMode() const;
bool isHolepunched() const;
bool useI2PSocket() const;
bool useUTPSocket() const;
bool useSSLSocket() const;
bool isRC4Encrypted() const;
bool isPlaintextEncrypted() const;
PeerAddress address() const;
QString client() const;
qreal progress() const;
int payloadUpSpeed() const;
int payloadDownSpeed() const;
qlonglong totalUpload() const;
qlonglong totalDownload() const;
QBitArray pieces() const;
QString connectionType() const;
#ifndef DISABLE_COUNTRIES_RESOLUTION
QString country() const;
#endif
private:
libtorrent::peer_info m_nativeInfo;
};
}
#endif // BITTORRENT_PEERINFO_H

View File

@@ -0,0 +1,96 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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.
*
* Contact : chris@qbittorrent.org
*/
#include <QTime>
#include <QDateTime>
#include "core/preferences.h"
#include "bandwidthscheduler.h"
BandwidthScheduler::BandwidthScheduler(QObject *parent)
: QTimer(parent)
{
Q_ASSERT(Preferences::instance()->isSchedulerEnabled());
// Single shot, we call start() again manually
setSingleShot(true);
// Connect Signals/Slots
connect(this, SIGNAL(timeout()), this, SLOT(start()));
}
void BandwidthScheduler::start()
{
const Preferences* const pref = Preferences::instance();
Q_ASSERT(pref->isSchedulerEnabled());
bool alt_bw_enabled = pref->isAltBandwidthEnabled();
QTime start = pref->getSchedulerStartTime();
QTime end = pref->getSchedulerEndTime();
QTime now = QTime::currentTime();
int sched_days = pref->getSchedulerDays();
int day = QDateTime::currentDateTime().toLocalTime().date().dayOfWeek();
bool new_mode = false;
bool reverse = false;
if (start > end) {
QTime temp = start;
start = end;
end = temp;
reverse = true;
}
if ((start <= now) && (end >= now)) {
switch(sched_days) {
case EVERY_DAY:
new_mode = true;
break;
case WEEK_ENDS:
if ((day == 6) || (day == 7))
new_mode = true;
break;
case WEEK_DAYS:
if ((day != 6) && (day != 7))
new_mode = true;
break;
default:
if (day == (sched_days - 2))
new_mode = true;
}
}
if (reverse)
new_mode = !new_mode;
if (new_mode != alt_bw_enabled)
emit switchToAlternativeMode(new_mode);
// Timeout regularly to accommodate for external system clock changes
// eg from the user or from a timesync utility
QTimer::start(1500);
}

View File

@@ -1,5 +1,5 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2010 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
@@ -28,31 +28,23 @@
* Contact : chris@qbittorrent.org
*/
#ifndef GEOIPMANAGER_H
#define GEOIPMANAGER_H
#ifndef BANDWIDTHSCHEDULER_H
#define BANDWIDTHSCHEDULER_H
#include <QString>
#include <QIcon>
#include <QTimer>
namespace libtorrent {
class session;
}
class GeoIPManager : public QObject {
Q_OBJECT
class BandwidthScheduler : public QTimer
{
Q_OBJECT
public:
static void loadDatabase(libtorrent::session *s);
static QIcon CountryISOCodeToIcon(const char* iso);
static QString CountryISOCodeToName(const char* iso);
BandwidthScheduler(QObject *parent = 0);
private:
static QString geoipFolder(bool embedded=false);
static QString geoipDBpath(bool embedded=false);
#ifdef WITH_GEOIP_EMBEDDED
static void exportEmbeddedDb();
#endif
public slots:
void start();
signals:
void switchToAlternativeMode(bool alternative);
};
#endif // GEOIP_H
#endif // BANDWIDTHSCHEDULER_H

View File

@@ -0,0 +1,439 @@
/*
* Bittorrent Client using Qt and libt.
* 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
* 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.
*
* Contact : chris@qbittorrent.org
*/
#include <QFile>
#include <QHostAddress>
#include <QDataStream>
#include <QStringList>
#include <libtorrent/session.hpp>
#include <libtorrent/ip_filter.hpp>
#include "core/logger.h"
#include "filterparserthread.h"
namespace libt = libtorrent;
FilterParserThread::FilterParserThread(libt::session *s, QObject *parent)
: QThread(parent)
, m_session(s)
, m_abort(false)
{
}
FilterParserThread::~FilterParserThread()
{
m_abort = true;
wait();
}
// Parser for eMule ip filter in DAT format
int FilterParserThread::parseDATFilterFile(QString m_filePath, libt::ip_filter &filter)
{
int ruleCount = 0;
QFile file(m_filePath);
if (!file.exists()) return ruleCount;
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
Logger::instance()->addMessage(tr("I/O Error: Could not open ip filter file in read mode."), Log::CRITICAL);
return ruleCount;
}
unsigned int nbLine = 0;
while (!file.atEnd() && !m_abort) {
++nbLine;
QByteArray line = file.readLine();
// Ignoring empty lines
line = line.trimmed();
if (line.isEmpty()) continue;
// Ignoring commented lines
if (line.startsWith('#') || line.startsWith("//")) continue;
// Line should be split by commas
QList<QByteArray> partsList = line.split(',');
const uint nbElem = partsList.size();
// IP Range should be split by a dash
QList<QByteArray> IPs = partsList.first().split('-');
if (IPs.size() != 2) {
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
qDebug("Line was %s", line.constData());
continue;
}
boost::system::error_code ec;
const QString strStartIP = cleanupIPAddress(IPs.at(0));
if (strStartIP.isEmpty()) {
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
qDebug("Start IP of the range is malformated: %s", qPrintable(strStartIP));
continue;
}
libt::address startAddr = libt::address::from_string(qPrintable(strStartIP), ec);
if (ec) {
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
qDebug("Start IP of the range is malformated: %s", qPrintable(strStartIP));
continue;
}
const QString strEndIP = cleanupIPAddress(IPs.at(1));
if (strEndIP.isEmpty()) {
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
qDebug("End IP of the range is malformated: %s", qPrintable(strEndIP));
continue;
}
libt::address endAddr = libt::address::from_string(qPrintable(strEndIP), ec);
if (ec) {
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
qDebug("End IP of the range is malformated: %s", qPrintable(strEndIP));
continue;
}
if (startAddr.is_v4() != endAddr.is_v4()) {
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
qDebug("One IP is IPv4 and the other is IPv6!");
continue;
}
// Check if there is an access value (apparently not mandatory)
int nbAccess = 0;
if (nbElem > 1) {
// There is possibly one
nbAccess = partsList.at(1).trimmed().toInt();
}
if (nbAccess > 127) {
// Ignoring this rule because access value is too high
continue;
}
// Now Add to the filter
try {
filter.add_rule(startAddr, endAddr, libt::ip_filter::blocked);
++ruleCount;
}
catch(std::exception &) {
qDebug("Bad line in filter file, avoided crash...");
}
}
file.close();
return ruleCount;
}
// Parser for PeerGuardian ip filter in p2p format
int FilterParserThread::parseP2PFilterFile(QString m_filePath, libt::ip_filter &filter)
{
int ruleCount = 0;
QFile file(m_filePath);
if (!file.exists()) return ruleCount;
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
Logger::instance()->addMessage(tr("I/O Error: Could not open ip filter file in read mode."), Log::CRITICAL);
return ruleCount;
}
unsigned int nbLine = 0;
while (!file.atEnd() && !m_abort) {
++nbLine;
QByteArray line = file.readLine().trimmed();
if (line.isEmpty()) continue;
// Ignoring commented lines
if (line.startsWith('#') || line.startsWith("//")) continue;
// Line is split by :
QList<QByteArray> partsList = line.split(':');
if (partsList.size() < 2) {
qDebug("p2p file: line %d is malformed.", nbLine);
continue;
}
// Get IP range
QList<QByteArray> IPs = partsList.last().split('-');
if (IPs.size() != 2) {
qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("line was: %s", line.constData());
continue;
}
boost::system::error_code ec;
QString strStartIP = cleanupIPAddress(IPs.at(0));
if (strStartIP.isEmpty()) {
qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("Start IP is invalid: %s", qPrintable(strStartIP));
continue;
}
libt::address startAddr = libt::address::from_string(qPrintable(strStartIP), ec);
if (ec) {
qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("Start IP is invalid: %s", qPrintable(strStartIP));
continue;
}
QString strEndIP = cleanupIPAddress(IPs.at(1));
if (strEndIP.isEmpty()) {
qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("End IP is invalid: %s", qPrintable(strStartIP));
continue;
}
libt::address endAddr = libt::address::from_string(qPrintable(strEndIP), ec);
if (ec) {
qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("End IP is invalid: %s", qPrintable(strStartIP));
continue;
}
if (startAddr.is_v4() != endAddr.is_v4()) {
qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("Line was: %s", line.constData());
continue;
}
try {
filter.add_rule(startAddr, endAddr, libt::ip_filter::blocked);
++ruleCount;
}
catch(std::exception &) {
qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("Line was: %s", line.constData());
continue;
}
}
file.close();
return ruleCount;
}
int FilterParserThread::getlineInStream(QDataStream &stream, std::string &name, char delim)
{
char c;
int total_read = 0;
int read;
do {
read = stream.readRawData(&c, 1);
total_read += read;
if (read > 0) {
if (c != delim) {
name += c;
}
else {
// Delim found
return total_read;
}
}
}
while(read > 0);
return total_read;
}
// Parser for PeerGuardian ip filter in p2p format
int FilterParserThread::parseP2BFilterFile(QString m_filePath, libt::ip_filter &filter)
{
int ruleCount = 0;
QFile file(m_filePath);
if (!file.exists()) return ruleCount;
if (!file.open(QIODevice::ReadOnly)) {
Logger::instance()->addMessage(tr("I/O Error: Could not open ip filter file in read mode."), Log::CRITICAL);
return ruleCount;
}
QDataStream stream(&file);
// Read header
char buf[7];
unsigned char version;
if (!stream.readRawData(buf, sizeof(buf))
|| memcmp(buf, "\xFF\xFF\xFF\xFFP2B", 7)
|| !stream.readRawData((char*)&version, sizeof(version))) {
Logger::instance()->addMessage(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
return ruleCount;
}
if ((version == 1) || (version == 2)) {
qDebug ("p2b version 1 or 2");
unsigned int start, end;
std::string name;
while(getlineInStream(stream, name, '\0') && !m_abort) {
if (!stream.readRawData((char*)&start, sizeof(start))
|| !stream.readRawData((char*)&end, sizeof(end))) {
Logger::instance()->addMessage(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
return ruleCount;
}
// Network byte order to Host byte order
// asio address_v4 constructor expects it
// that way
libt::address_v4 first(ntohl(start));
libt::address_v4 last(ntohl(end));
// Apply to bittorrent session
try {
filter.add_rule(first, last, libt::ip_filter::blocked);
++ruleCount;
}
catch(std::exception &) {}
}
}
else if (version == 3) {
qDebug ("p2b version 3");
unsigned int namecount;
if (!stream.readRawData((char*)&namecount, sizeof(namecount))) {
Logger::instance()->addMessage(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
return ruleCount;
}
namecount = ntohl(namecount);
// Reading names although, we don't really care about them
for (unsigned int i = 0; i < namecount; ++i) {
std::string name;
if (!getlineInStream(stream, name, '\0')) {
Logger::instance()->addMessage(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
return ruleCount;
}
if (m_abort) return ruleCount;
}
// Reading the ranges
unsigned int rangecount;
if (!stream.readRawData((char*)&rangecount, sizeof(rangecount))) {
Logger::instance()->addMessage(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
return ruleCount;
}
rangecount = ntohl(rangecount);
unsigned int name, start, end;
for (unsigned int i = 0; i < rangecount; ++i) {
if (!stream.readRawData((char*)&name, sizeof(name))
|| !stream.readRawData((char*)&start, sizeof(start))
|| !stream.readRawData((char*)&end, sizeof(end))) {
Logger::instance()->addMessage(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
return ruleCount;
}
// Network byte order to Host byte order
// asio address_v4 constructor expects it
// that way
libt::address_v4 first(ntohl(start));
libt::address_v4 last(ntohl(end));
// Apply to bittorrent session
try {
filter.add_rule(first, last, libt::ip_filter::blocked);
++ruleCount;
}
catch(std::exception &) {}
if (m_abort) return ruleCount;
}
}
else {
Logger::instance()->addMessage(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
}
file.close();
return ruleCount;
}
// Process ip filter file
// Supported formats:
// * eMule IP list (DAT): http://wiki.phoenixlabs.org/wiki/DAT_Format
// * PeerGuardian Text (P2P): http://wiki.phoenixlabs.org/wiki/P2P_Format
// * PeerGuardian Binary (P2B): http://wiki.phoenixlabs.org/wiki/P2B_Format
void FilterParserThread::processFilterFile(QString _filePath)
{
if (isRunning()) {
// Already parsing a filter, m_abort first
m_abort = true;
wait();
}
m_abort = false;
m_filePath = _filePath;
// Run it
start();
}
void FilterParserThread::processFilterList(libt::session *s, const QStringList &IPs)
{
// First, import current filter
libt::ip_filter filter = s->get_ip_filter();
foreach (const QString &ip, IPs) {
qDebug("Manual ban of peer %s", ip.toLocal8Bit().constData());
boost::system::error_code ec;
libt::address addr = libt::address::from_string(ip.toLocal8Bit().constData(), ec);
Q_ASSERT(!ec);
if (!ec)
filter.add_rule(addr, addr, libt::ip_filter::blocked);
}
s->set_ip_filter(filter);
}
QString FilterParserThread::cleanupIPAddress(QString _ip)
{
QHostAddress ip(_ip.trimmed());
if (ip.isNull()) return QString();
return ip.toString();
}
void FilterParserThread::run()
{
qDebug("Processing filter file");
libt::ip_filter filter = m_session->get_ip_filter();
int ruleCount = 0;
if (m_filePath.endsWith(".p2p", Qt::CaseInsensitive)) {
// PeerGuardian p2p file
ruleCount = parseP2PFilterFile(m_filePath, filter);
}
else if (m_filePath.endsWith(".p2b", Qt::CaseInsensitive)) {
// PeerGuardian p2b file
ruleCount = parseP2BFilterFile(m_filePath, filter);
}
else if (m_filePath.endsWith(".dat", Qt::CaseInsensitive)) {
// eMule DAT format
ruleCount = parseDATFilterFile(m_filePath, filter);
}
if (m_abort) return;
try {
m_session->set_ip_filter(filter);
emit IPFilterParsed(ruleCount);
}
catch(std::exception &) {
emit IPFilterError();
}
qDebug("IP Filter thread: finished parsing, filter applied");
}

View File

@@ -1,5 +1,5 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
@@ -32,38 +32,30 @@
#define FILTERPARSERTHREAD_H
#include <QThread>
#include <QDataStream>
#include <QStringList>
namespace libtorrent {
class session;
struct ip_filter;
class QDataStream;
class QStringList;
namespace libtorrent
{
class session;
struct ip_filter;
}
using namespace std;
// P2B Stuff
#include <string.h>
#ifdef Q_OS_WIN
#include <Winsock2.h>
#else
#include <arpa/inet.h>
#endif
// End of P2B stuff
class FilterParserThread : public QThread {
class FilterParserThread : public QThread
{
Q_OBJECT
public:
FilterParserThread(QObject* parent, libtorrent::session *s);
FilterParserThread(libtorrent::session *s, QObject *parent = 0);
~FilterParserThread();
int parseDATFilterFile(QString filePath, libtorrent::ip_filter& filter);
int parseP2PFilterFile(QString filePath, libtorrent::ip_filter& filter);
int getlineInStream(QDataStream& stream, string& name, char delim);
int parseP2BFilterFile(QString filePath, libtorrent::ip_filter& filter);
int parseDATFilterFile(QString filePath, libtorrent::ip_filter &filter);
int parseP2PFilterFile(QString filePath, libtorrent::ip_filter &filter);
int getlineInStream(QDataStream &stream, std::string &name, char delim);
int parseP2BFilterFile(QString filePath, libtorrent::ip_filter &filter);
void processFilterFile(QString _filePath);
static void processFilterList(libtorrent::session *s, const QStringList& IPs);
static void processFilterList(libtorrent::session *s, const QStringList &IPs);
signals:
void IPFilterParsed(int ruleCount);
@@ -74,9 +66,9 @@ protected:
void run();
private:
libtorrent::session *s;
bool abort;
QString filePath;
libtorrent::session *m_session;
bool m_abort;
QString m_filePath;
};
#endif
#endif // BITTORRENT_FILTERPARSERTHREAD_H

View File

@@ -0,0 +1,56 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2011 Christophe Dumez <chris@qbittorrent.org>
*
* 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 <QList>
#include "speedmonitor.h"
void SpeedMonitor::addSample(const SpeedSample &sample)
{
m_speedSamples.push_back(sample);
m_sum += sample;
if (m_speedSamples.size() > MAX_SAMPLES) {
m_sum -= m_speedSamples.front();
m_speedSamples.pop_front();
}
}
SpeedSampleAvg SpeedMonitor::average() const
{
if (m_speedSamples.empty())
return SpeedSampleAvg();
qreal k = qreal(1.) / m_speedSamples.size();
return SpeedSampleAvg(m_sum.download * k, m_sum.upload * k);
}
void SpeedMonitor::reset()
{
m_sum = SpeedSample();
m_speedSamples.clear();
}

View File

@@ -1,6 +1,7 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2011 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -26,42 +27,58 @@
* exception statement from your version.
*/
#ifndef QTORRENTFILTER_H
#define QTORRENTFILTER_H
#ifndef SPEEDMONITOR_H
#define SPEEDMONITOR_H
#include "qtorrenthandle.h"
template<typename T> class QList;
class QTorrentFilter
template<typename T>
struct Sample
{
public:
enum
Sample()
: download()
, upload()
{
All,
Downloading,
Seeding,
Completed,
Paused,
Resumed,
Active,
Inactive
};
}
// label: pass empty string for "no label" or null string (QString()) for "any label"
QTorrentFilter(QString filter, QString label = QString());
bool apply(const QTorrentHandle& h) const;
Sample(T dl, T ul)
: download(dl)
, upload(ul)
{
}
private:
int type_;
QString label_;
Sample<T> &operator+=(const Sample<T> &other)
{
download += other.download;
upload += other.upload;
return *this;
}
bool isTorrentDownloading(const QTorrentHandle &h) const;
bool isTorrentSeeding(const QTorrentHandle &h) const;
bool isTorrentCompleted(const QTorrentHandle &h) const;
bool isTorrentPaused(const QTorrentHandle &h) const;
bool isTorrentResumed(const QTorrentHandle &h) const;
bool isTorrentActive(const QTorrentHandle &h) const;
bool isTorrentInactive(const QTorrentHandle &h) const;
bool torrentHasLabel(const QTorrentHandle &h) const;
Sample<T> &operator-=(const Sample<T> &other)
{
download -= other.download;
upload -= other.upload;
return *this;
}
T download;
T upload;
};
#endif // QTORRENTFILTER_H
typedef Sample<qlonglong> SpeedSample;
typedef Sample<qreal> SpeedSampleAvg;
class SpeedMonitor
{
public:
void addSample(const SpeedSample &sample);
SpeedSampleAvg average() const;
void reset();
private:
static const int MAX_SAMPLES = 30;
QList<SpeedSample> m_speedSamples;
SpeedSample m_sum;
};
#endif // SPEEDMONITOR_H

View File

@@ -1,67 +1,81 @@
#include "torrentstatistics.h"
#include <QDateTime>
#include <libtorrent/session.hpp>
#include "qbtsession.h"
#include "qinisettings.h"
#include "preferences.h"
#include "core/qinisettings.h"
#include "core/preferences.h"
#include "core/bittorrent/sessionstatus.h"
#include "core/bittorrent/session.h"
#include "statistics.h"
TorrentStatistics::TorrentStatistics(QBtSession* session, QObject* parent)
: QObject(parent)
static const qint64 SAVE_INTERVAL = 15 * 60 * 1000;
namespace libt = libtorrent;
using namespace BitTorrent;
Statistics::Statistics(Session *session)
: QObject(session)
, m_session(session)
, m_sessionUL(0)
, m_sessionDL(0)
, m_lastWrite(0)
, m_dirty(false)
{
loadStats();
connect(&m_timer, SIGNAL(timeout()), this, SLOT(gatherStats()));
load();
connect(&m_timer, SIGNAL(timeout()), this, SLOT(gather()));
m_timer.start(60 * 1000);
}
TorrentStatistics::~TorrentStatistics() {
Statistics::~Statistics()
{
if (m_dirty)
m_lastWrite = 0;
saveStats();
save();
}
quint64 TorrentStatistics::getAlltimeDL() const {
quint64 Statistics::getAlltimeDL() const
{
return m_alltimeDL + m_sessionDL;
}
quint64 TorrentStatistics::getAlltimeUL() const {
quint64 Statistics::getAlltimeUL() const
{
return m_alltimeUL + m_sessionUL;
}
void TorrentStatistics::gatherStats() {
libtorrent::session_status ss = m_session->getSessionStatus();
if (ss.total_download > m_sessionDL) {
m_sessionDL = ss.total_download;
void Statistics::gather()
{
SessionStatus ss = m_session->status();
if (ss.totalDownload() > m_sessionDL) {
m_sessionDL = ss.totalDownload();
m_dirty = true;
}
if (ss.total_upload > m_sessionUL) {
m_sessionUL = ss.total_upload;
if (ss.totalUpload() > m_sessionUL) {
m_sessionUL = ss.totalUpload();
m_dirty = true;
}
saveStats();
save();
}
void TorrentStatistics::saveStats() const {
if (!(m_dirty && (QDateTime::currentMSecsSinceEpoch() - m_lastWrite >= 15*60*1000) ))
void Statistics::save() const
{
qint64 now = QDateTime::currentMSecsSinceEpoch();
if (!m_dirty || ((now - m_lastWrite) < SAVE_INTERVAL))
return;
QIniSettings s("qBittorrent", "qBittorrent-data");
QVariantHash v;
v.insert("AlltimeDL", m_alltimeDL + m_sessionDL);
v.insert("AlltimeUL", m_alltimeUL + m_sessionUL);
s.setValue("Stats/AllStats", v);
m_dirty = false;
m_lastWrite = QDateTime::currentMSecsSinceEpoch();
m_lastWrite = now;
}
void TorrentStatistics::loadStats() {
void Statistics::load()
{
// Temp code. Versions v3.1.4 and v3.1.5 saved the data in the qbittorrent.ini file.
// This code reads the data from there, writes it to the new file, and removes the keys
// from the old file. This code should be removed after some time has passed.
@@ -69,7 +83,7 @@ void TorrentStatistics::loadStats() {
// Don't forget to remove:
// 1. Preferences::getStats()
// 2. Preferences::removeStats()
// 3. #include "preferences.h"
// 3. #include "core/preferences.h"
Preferences* const pref = Preferences::instance();
QIniSettings s("qBittorrent", "qBittorrent-data");
QVariantHash v = pref->getStats();
@@ -87,14 +101,15 @@ void TorrentStatistics::loadStats() {
v["AlltimeUL"] = v["AlltimeUL"].toULongLong() + tmp["AlltimeUL"].toULongLong();
}
}
else
else {
v = s.value("Stats/AllStats").toHash();
}
m_alltimeDL = v["AlltimeDL"].toULongLong();
m_alltimeUL = v["AlltimeUL"].toULongLong();
if (m_dirty) {
saveStats();
save();
pref->removeStats();
}
}

View File

@@ -1,32 +1,32 @@
#ifndef TORRENTSTATISTICS_H
#define TORRENTSTATISTICS_H
#ifndef STATISTICS_H
#define STATISTICS_H
#include <QObject>
#include <QTimer>
class QBtSession;
namespace BitTorrent { class Session; }
class TorrentStatistics : QObject
class Statistics : QObject
{
Q_OBJECT
Q_DISABLE_COPY(TorrentStatistics)
Q_DISABLE_COPY(Statistics)
public:
TorrentStatistics(QBtSession* session, QObject* parent = 0);
~TorrentStatistics();
Statistics(BitTorrent::Session *session);
~Statistics();
quint64 getAlltimeDL() const;
quint64 getAlltimeUL() const;
private slots:
void gatherStats();
void gather();
private:
void saveStats() const;
void loadStats();
void save() const;
void load();
private:
QBtSession* m_session;
BitTorrent::Session *m_session;
// Will overflow at 15.9 EiB
quint64 m_alltimeUL;
quint64 m_alltimeDL;
@@ -38,4 +38,4 @@ private:
QTimer m_timer;
};
#endif // TORRENTSTATISTICS_H
#endif // STATISTICS_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,376 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* 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 BITTORRENT_SESSION_H
#define BITTORRENT_SESSION_H
#include <QFile>
#include <QHash>
#include <QPointer>
#include <QVector>
#include <QMutex>
#include <QWaitCondition>
#include <QNetworkConfigurationManager>
#include "core/tristatebool.h"
#include "core/types.h"
#include "torrentinfo.h"
namespace libtorrent
{
class session;
class entry;
struct add_torrent_params;
struct pe_settings;
struct proxy_settings;
struct session_settings;
struct session_status;
class alert;
struct torrent_alert;
struct state_update_alert;
struct stats_alert;
struct add_torrent_alert;
struct torrent_checked_alert;
struct torrent_finished_alert;
struct torrent_removed_alert;
struct torrent_deleted_alert;
struct torrent_delete_failed_alert;
struct torrent_paused_alert;
struct torrent_resumed_alert;
struct save_resume_data_alert;
struct save_resume_data_failed_alert;
struct file_renamed_alert;
struct storage_moved_alert;
struct storage_moved_failed_alert;
struct metadata_received_alert;
struct file_error_alert;
struct file_completed_alert;
struct tracker_error_alert;
struct tracker_reply_alert;
struct tracker_warning_alert;
struct portmap_error_alert;
struct portmap_alert;
struct peer_blocked_alert;
struct peer_ban_alert;
struct fastresume_rejected_alert;
struct url_seed_alert;
struct listen_succeeded_alert;
struct listen_failed_alert;
struct external_ip_alert;
}
class QTimer;
class QStringList;
class QString;
class QUrl;
template<typename T> class QList;
class FilterParserThread;
class BandwidthScheduler;
class Statistics;
typedef QPair<QString, QString> QStringPair;
namespace BitTorrent
{
class InfoHash;
class CacheStatus;
class SessionStatus;
class TorrentHandle;
class Tracker;
class MagnetUri;
class TrackerEntry;
struct AddTorrentData;
struct AddTorrentParams
{
QString name;
QString label;
QString savePath;
bool disableTempPath; // e.g. for imported torrents
bool sequential;
TriStateBool addForced;
TriStateBool addPaused;
QVector<int> filePriorities; // used if TorrentInfo is set
bool ignoreShareRatio;
bool skipChecking;
AddTorrentParams();
};
struct TorrentStatusReport
{
uint nbDownloading = 0;
uint nbSeeding = 0;
uint nbCompleted = 0;
uint nbActive = 0;
uint nbInactive = 0;
uint nbPaused = 0;
uint nbResumed = 0;
uint nbErrored = 0;
};
class Session : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Session)
public:
static void initInstance();
static void freeInstance();
static Session *instance();
bool isDHTEnabled() const;
bool isLSDEnabled() const;
bool isPexEnabled() const;
bool isQueueingEnabled() const;
qreal globalMaxRatio() const;
bool isTempPathEnabled() const;
bool isAppendExtensionEnabled() const;
bool useAppendLabelToSavePath() const;
QString defaultSavePath() const;
QString tempPath() const;
TorrentHandle *findTorrent(const InfoHash &hash) const;
QHash<InfoHash, TorrentHandle *> torrents() const;
TorrentStatusReport torrentStatusReport() const;
bool hasActiveTorrents() const;
bool hasUnfinishedTorrents() const;
SessionStatus status() const;
CacheStatus cacheStatus() const;
quint64 getAlltimeDL() const;
quint64 getAlltimeUL() const;
int downloadRateLimit() const;
int uploadRateLimit() const;
bool isListening() const;
void changeSpeedLimitMode(bool alternative);
void setDownloadRateLimit(int rate);
void setUploadRateLimit(int rate);
void setGlobalMaxRatio(qreal ratio);
void enableIPFilter(const QString &filterPath, bool force = false);
void disableIPFilter();
void banIP(const QString &ip);
bool isKnownTorrent(const InfoHash &hash) const;
bool addTorrent(QString source, const AddTorrentParams &params = AddTorrentParams());
bool addTorrent(const TorrentInfo &torrentInfo, const AddTorrentParams &params = AddTorrentParams());
bool deleteTorrent(const QString &hash, bool deleteLocalFiles = false);
bool loadMetadata(const QString &magnetUri);
bool cancelLoadMetadata(const InfoHash &hash);
void recursiveTorrentDownload(const InfoHash &hash);
void increaseTorrentsPriority(const QStringList &hashes);
void decreaseTorrentsPriority(const QStringList &hashes);
void topTorrentsPriority(const QStringList &hashes);
void bottomTorrentsPriority(const QStringList &hashes);
// TorrentHandle interface
void handleTorrentRatioLimitChanged(TorrentHandle *const torrent);
void handleTorrentSavePathChanged(TorrentHandle *const torrent);
void handleTorrentLabelChanged(TorrentHandle *const torrent, const QString &oldLabel);
void handleTorrentMetadataReceived(TorrentHandle *const torrent);
void handleTorrentPaused(TorrentHandle *const torrent);
void handleTorrentResumed(TorrentHandle *const torrent);
void handleTorrentChecked(TorrentHandle *const torrent);
void handleTorrentFinished(TorrentHandle *const torrent);
void handleTorrentTrackersAdded(TorrentHandle *const torrent, const QList<TrackerEntry> &newTrackers);
void handleTorrentTrackersRemoved(TorrentHandle *const torrent, const QList<TrackerEntry> &deletedTrackers);
void handleTorrentTrackersChanged(TorrentHandle *const torrent);
void handleTorrentUrlSeedsAdded(TorrentHandle *const torrent, const QList<QUrl> &newUrlSeeds);
void handleTorrentUrlSeedsRemoved(TorrentHandle *const torrent, const QList<QUrl> &urlSeeds);
void handleTorrentResumeDataReady(TorrentHandle *const torrent, const libtorrent::entry &data);
void handleTorrentResumeDataFailed(TorrentHandle *const torrent);
void handleTorrentTrackerReply(TorrentHandle *const torrent, const QString &trackerUrl);
void handleTorrentTrackerWarning(TorrentHandle *const torrent, const QString &trackerUrl);
void handleTorrentTrackerError(TorrentHandle *const torrent, const QString &trackerUrl);
void handleTorrentTrackerAuthenticationRequired(TorrentHandle *const torrent, const QString &trackerUrl);
signals:
void torrentsUpdated();
void addTorrentFailed(const QString &error);
void torrentAdded(BitTorrent::TorrentHandle *const torrent);
void torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent);
void torrentPaused(BitTorrent::TorrentHandle *const torrent);
void torrentResumed(BitTorrent::TorrentHandle *const torrent);
void torrentFinished(BitTorrent::TorrentHandle *const torrent);
void torrentFinishedChecking(BitTorrent::TorrentHandle *const torrent);
void torrentSavePathChanged(BitTorrent::TorrentHandle *const torrent);
void torrentLabelChanged(BitTorrent::TorrentHandle *const torrent, const QString &oldLabel);
void allTorrentsFinished();
void metadataLoaded(const BitTorrent::TorrentInfo &info);
void torrentMetadataLoaded(BitTorrent::TorrentHandle *const torrent);
void fullDiskError(BitTorrent::TorrentHandle *const torrent, const QString &msg);
void trackerSuccess(BitTorrent::TorrentHandle *const torrent, const QString &tracker);
void trackerWarning(BitTorrent::TorrentHandle *const torrent, const QString &tracker);
void trackerError(BitTorrent::TorrentHandle *const torrent, const QString &tracker);
void trackerAuthenticationRequired(BitTorrent::TorrentHandle *const torrent);
void recursiveTorrentDownloadPossible(BitTorrent::TorrentHandle *const torrent);
void speedLimitModeChanged(bool alternative);
void ipFilterParsed(bool error, int ruleCount);
void trackersAdded(BitTorrent::TorrentHandle *const torrent, const QList<BitTorrent::TrackerEntry> &trackers);
void trackersRemoved(BitTorrent::TorrentHandle *const torrent, const QList<BitTorrent::TrackerEntry> &trackers);
void trackersChanged(BitTorrent::TorrentHandle *const torrent);
void trackerlessStateChanged(BitTorrent::TorrentHandle *const torrent, bool trackerless);
void downloadFromUrlFailed(const QString &url, const QString &reason);
void downloadFromUrlFinished(const QString &url);
private slots:
void configure();
void readAlerts();
void refresh();
void processBigRatios();
void generateResumeData(bool final = false);
void handleIPFilterParsed(int ruleCount);
void handleIPFilterError();
void handleDownloadFinished(const QString &url, const QString &filePath);
void handleDownloadFailed(const QString &url, const QString &reason);
void handleRedirectedToMagnet(const QString &url, const QString &magnetUri);
void switchToAlternativeMode(bool alternative);
// Session reconfiguration triggers
void networkOnlineStateChanged(const bool online);
void networkConfigurationChange(const QNetworkConfiguration&);
private:
explicit Session(QObject *parent = 0);
~Session();
bool hasPerTorrentRatioLimit() const;
void initResumeFolder();
// Session configuration
void setSessionSettings();
void setProxySettings(libtorrent::proxy_settings proxySettings);
void adjustLimits();
void adjustLimits(libtorrent::session_settings &sessionSettings);
const QStringList getListeningIPs();
void setListeningPort();
void setDefaultSavePath(const QString &path);
void setDefaultTempPath(const QString &path = QString());
void preAllocateAllFiles(bool b);
void setMaxConnectionsPerTorrent(int max);
void setMaxUploadsPerTorrent(int max);
void enableLSD(bool enable);
void enableDHT(bool enable);
void changeSpeedLimitMode_impl(bool alternative);
void setAppendLabelToSavePath(bool append);
void setAppendExtension(bool append);
void startUpTorrents();
bool addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri,
const TorrentInfo &torrentInfo = TorrentInfo(),
const QByteArray &fastresumeData = QByteArray());
void updateRatioTimer();
void exportTorrentFile(TorrentHandle *const torrent, TorrentExportFolder folder = TorrentExportFolder::Regular);
void exportTorrentFiles(QString path);
void saveTorrentResumeData(TorrentHandle *const torrent);
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(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);
void handleTorrentDeleteFailedAlert(libtorrent::torrent_delete_failed_alert *p);
void handlePortmapWarningAlert(libtorrent::portmap_error_alert *p);
void handlePortmapAlert(libtorrent::portmap_alert *p);
void handlePeerBlockedAlert(libtorrent::peer_blocked_alert *p);
void handlePeerBanAlert(libtorrent::peer_ban_alert *p);
void handleUrlSeedAlert(libtorrent::url_seed_alert *p);
void handleListenSucceededAlert(libtorrent::listen_succeeded_alert *p);
void handleListenFailedAlert(libtorrent::listen_failed_alert *p);
void handleExternalIPAlert(libtorrent::external_ip_alert *p);
void saveResumeData();
bool writeResumeDataFile(TorrentHandle *const torrent, const libtorrent::entry &data);
void dispatchAlerts(std::auto_ptr<libtorrent::alert> alertPtr);
void getPendingAlerts(QVector<libtorrent::alert *> &out, ulong time = 0);
AddTorrentData addDataFromParams(const AddTorrentParams &params);
// BitTorrent
libtorrent::session *m_nativeSession;
bool m_LSDEnabled;
bool m_DHTEnabled;
bool m_PeXEnabled;
bool m_queueingEnabled;
bool m_torrentExportEnabled;
bool m_finishedTorrentExportEnabled;
bool m_preAllocateAll;
qreal m_globalMaxRatio;
int m_numResumeData;
int m_extraLimit;
bool m_appendLabelToSavePath;
bool m_appendExtension;
uint m_refreshInterval;
MaxRatioAction m_highRatioAction;
QList<BitTorrent::TrackerEntry> m_additionalTrackers;
QString m_defaultSavePath;
QString m_tempPath;
QString m_filterPath;
QString m_resumeFolderPath;
QFile m_resumeFolderLock;
QHash<InfoHash, QString> m_savePathsToRemove;
QTimer *m_refreshTimer;
QTimer *m_bigRatioTimer;
QTimer *m_resumeDataTimer;
Statistics *m_statistics;
// IP filtering
QPointer<FilterParserThread> m_filterParser;
QPointer<BandwidthScheduler> m_bwScheduler;
// Tracker
QPointer<Tracker> m_tracker;
QHash<InfoHash, TorrentInfo> m_loadedMetadata;
QHash<InfoHash, TorrentHandle *> m_torrents;
QHash<InfoHash, AddTorrentData> m_addingTorrents;
QHash<QString, AddTorrentParams> m_downloadedTorrents;
TorrentStatusReport m_torrentStatusReport;
QMutex m_alertsMutex;
QWaitCondition m_alertsWaitCondition;
QVector<libtorrent::alert *> m_alerts;
QNetworkConfigurationManager m_networkManager;
static Session *m_instance;
};
}
#endif // BITTORRENT_SESSION_H

View File

@@ -0,0 +1,136 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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 "sessionstatus.h"
using namespace BitTorrent;
SessionStatus::SessionStatus(const libtorrent::session_status &nativeStatus)
: m_nativeStatus(nativeStatus)
{
}
bool SessionStatus::hasIncomingConnections() const
{
return m_nativeStatus.has_incoming_connections;
}
int SessionStatus::payloadDownloadRate() const
{
return m_nativeStatus.payload_download_rate;
}
int SessionStatus::payloadUploadRate() const
{
return m_nativeStatus.payload_upload_rate;
}
int SessionStatus::downloadRate() const
{
return m_nativeStatus.download_rate;
}
int SessionStatus::uploadRate() const
{
return m_nativeStatus.upload_rate;
}
int SessionStatus::ipOverheadDownloadRate() const
{
return m_nativeStatus.ip_overhead_download_rate;
}
int SessionStatus::ipOverheadUploadRate() const
{
return m_nativeStatus.ip_overhead_upload_rate;
}
int SessionStatus::dhtDownloadRate() const
{
return m_nativeStatus.dht_download_rate;
}
int SessionStatus::dhtUploadRate() const
{
return m_nativeStatus.dht_upload_rate;
}
int SessionStatus::trackerDownloadRate() const
{
return m_nativeStatus.tracker_download_rate;
}
int SessionStatus::trackerUploadRate() const
{
return m_nativeStatus.tracker_upload_rate;
}
qlonglong SessionStatus::totalDownload() const
{
return m_nativeStatus.total_download;
}
qlonglong SessionStatus::totalUpload() const
{
return m_nativeStatus.total_upload;
}
qlonglong SessionStatus::totalPayloadDownload() const
{
return m_nativeStatus.total_payload_download;
}
qlonglong SessionStatus::totalPayloadUpload() const
{
return m_nativeStatus.total_payload_upload;
}
qlonglong SessionStatus::totalWasted() const
{
return (m_nativeStatus.total_redundant_bytes + m_nativeStatus.total_failed_bytes);
}
int SessionStatus::diskReadQueue() const
{
return m_nativeStatus.disk_read_queue;
}
int SessionStatus::diskWriteQueue() const
{
return m_nativeStatus.disk_write_queue;
}
int SessionStatus::dhtNodes() const
{
return m_nativeStatus.dht_nodes;
}
int SessionStatus::peersCount() const
{
return m_nativeStatus.num_peers;
}

View File

@@ -0,0 +1,79 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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 BITTORRENT_SESSIONSTATUS_H
#define BITTORRENT_SESSIONSTATUS_H
#include <libtorrent/session_status.hpp>
#include <QtGlobal>
namespace BitTorrent
{
class SessionStatus
{
public:
SessionStatus(const libtorrent::session_status &nativeStatus);
bool hasIncomingConnections() const;
// Return current download rate for the BT
// session. Payload means that it only take into
// account "useful" part of the rate
int payloadDownloadRate() const;
// Return current upload rate for the BT
// session. Payload means that it only take into
// account "useful" part of the rate
int payloadUploadRate() const;
// Additional download/upload rates
int uploadRate() const;
int downloadRate() const;
int ipOverheadUploadRate() const;
int ipOverheadDownloadRate() const;
int dhtUploadRate() const;
int dhtDownloadRate() const;
int trackerUploadRate() const;
int trackerDownloadRate() const;
qlonglong totalDownload() const;
qlonglong totalUpload() const;
qlonglong totalPayloadDownload() const;
qlonglong totalPayloadUpload() const;
qlonglong totalWasted() const;
int diskReadQueue() const;
int diskWriteQueue() const;
int dhtNodes() const;
int peersCount() const;
private:
libtorrent::session_status m_nativeStatus;
};
}
#endif // BITTORRENT_SESSIONSTATUS_H

View File

@@ -0,0 +1,165 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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.
*
* Contact : chris@qbittorrent.org
*/
#include <libtorrent/entry.hpp>
#include <libtorrent/bencode.hpp>
#include <libtorrent/torrent_info.hpp>
#include <libtorrent/file.hpp>
#include <libtorrent/storage.hpp>
#include <libtorrent/hasher.hpp>
#include <libtorrent/file_pool.hpp>
#include <libtorrent/create_torrent.hpp>
#include <QFile>
#include <QDir>
#include <boost/bind.hpp>
#include <iostream>
#include <fstream>
#include "core/utils/fs.h"
#include "core/utils/misc.h"
#include "core/utils/string.h"
#include "torrentcreatorthread.h"
namespace libt = libtorrent;
using namespace BitTorrent;
// do not include files and folders whose
// name starts with a .
bool fileFilter(const std::string &f)
{
return (libt::filename(f)[0] != '.');
}
TorrentCreatorThread::TorrentCreatorThread(QObject *parent)
: QThread(parent)
{
}
TorrentCreatorThread::~TorrentCreatorThread()
{
m_abort = true;
wait();
}
void TorrentCreatorThread::create(const QString &inputPath, const QString &savePath, const QStringList &trackers,
const QStringList &urlSeeds, const QString &comment, bool isPrivate, int pieceSize)
{
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;
m_abort = false;
start();
}
void TorrentCreatorThread::sendProgressSignal(int numHashes, int numPieces)
{
emit updateProgress(static_cast<int>((numHashes * 100.) / numPieces));
}
void TorrentCreatorThread::abortCreation()
{
m_abort = true;
}
void TorrentCreatorThread::run()
{
emit updateProgress(0);
QString creator_str("qBittorrent " VERSION);
try {
libt::file_storage fs;
// Adding files to the torrent
libt::add_files(fs, Utils::String::toStdString(Utils::Fs::toNativePath(m_inputPath)), fileFilter);
if (m_abort) return;
libt::create_torrent t(fs, m_pieceSize);
// Add url seeds
foreach (const QString &seed, m_urlSeeds)
t.add_url_seed(Utils::String::toStdString(seed.trimmed()));
int tier = 0;
bool newline = false;
foreach (const QString &tracker, m_trackers) {
if (tracker.isEmpty()) {
if (newline)
continue;
++tier;
newline = true;
continue;
}
t.add_tracker(Utils::String::toStdString(tracker.trimmed()), tier);
newline = false;
}
if (m_abort) return;
// calculate the hash for all pieces
const QString parentPath = Utils::Fs::branchPath(m_inputPath) + "/";
libt::set_piece_hashes(t, Utils::String::toStdString(Utils::Fs::toNativePath(parentPath)), boost::bind(&TorrentCreatorThread::sendProgressSignal, this, _1, t.num_pieces()));
// Set qBittorrent as creator and add user comment to
// torrent_info structure
t.set_creator(creator_str.toUtf8().constData());
t.set_comment(m_comment.toUtf8().constData());
// Is private ?
t.set_priv(m_private);
if (m_abort) return;
// create the torrent and print it to out
qDebug("Saving to %s", qPrintable(m_savePath));
#ifdef _MSC_VER
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
std::ofstream outfile(Utils::Fs::toNativePath(m_savePath).toLocal8Bit().constData(), std::ios_base::out | std::ios_base::binary);
#endif
if (outfile.fail())
throw std::exception();
libt::bencode(std::ostream_iterator<char>(outfile), t.generate());
outfile.close();
emit updateProgress(100);
emit creationSuccess(m_savePath, parentPath);
}
catch (std::exception& e) {
emit creationFailure(Utils::String::fromStdString(e.what()));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2010 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
@@ -28,46 +28,46 @@
* Contact : chris@qbittorrent.org
*/
#ifndef TORRENTCREATORTHREAD_H
#define TORRENTCREATORTHREAD_H
#ifndef BITTORRENT_TORRENTCREATORTHREAD_H
#define BITTORRENT_TORRENTCREATORTHREAD_H
#include <QThread>
#include <QStringList>
#include <QDialog>
class TorrentCreatorThread : public QThread {
Q_OBJECT
namespace BitTorrent
{
class TorrentCreatorThread : public QThread
{
Q_OBJECT
public:
TorrentCreatorThread(QDialog *_parent) {
parent = _parent;
}
~TorrentCreatorThread() {
abort = true;
wait();
}
void create(QString _input_path, QString _save_path, QStringList _trackers, QStringList _url_seeds, QString _comment, bool _is_private, int _piece_size);
void sendProgressSignal(int progress);
void abortCreation() { abort = true; }
public:
TorrentCreatorThread(QObject *parent = 0);
~TorrentCreatorThread();
protected:
void run();
void create(const QString &inputPath, const QString &savePath, const QStringList &trackers,
const QStringList &urlSeeds, const QString &comment, bool isPrivate, int pieceSize);
void abortCreation();
signals:
void creationFailure(QString msg);
void creationSuccess(QString path, QString branch_path);
void updateProgress(int progress);
protected:
void run();
private:
QString input_path;
QString save_path;
QStringList trackers;
QStringList url_seeds;
QString comment;
bool is_private;
int piece_size;
bool abort;
QDialog *parent;
};
signals:
void creationFailure(const QString &msg);
void creationSuccess(const QString &path, const QString &branchPath);
void updateProgress(int progress);
#endif // TORRENTCREATORTHREAD_H
private:
void sendProgressSignal(int numHashes, int numPieces);
QString m_inputPath;
QString m_savePath;
QStringList m_trackers;
QStringList m_urlSeeds;
QString m_comment;
bool m_private;
int m_pieceSize;
bool m_abort;
};
}
#endif // BITTORRENT_TORRENTCREATORTHREAD_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,418 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* 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 BITTORRENT_TORRENTHANDLE_H
#define BITTORRENT_TORRENTHANDLE_H
#include <QObject>
#include <QString>
#include <QDateTime>
#include <QQueue>
#include <QVector>
#include <QHash>
#include <libtorrent/torrent_handle.hpp>
#include <boost/function.hpp>
#include "core/tristatebool.h"
#include "private/speedmonitor.h"
#include "infohash.h"
#include "torrentinfo.h"
class QBitArray;
class QStringList;
template<typename T, typename U> struct QPair;
namespace libtorrent
{
class alert;
struct stats_alert;
struct torrent_checked_alert;
struct torrent_finished_alert;
struct torrent_paused_alert;
struct torrent_resumed_alert;
struct save_resume_data_alert;
struct save_resume_data_failed_alert;
struct file_renamed_alert;
struct file_rename_failed_alert;
struct storage_moved_alert;
struct storage_moved_failed_alert;
struct metadata_received_alert;
struct file_completed_alert;
struct tracker_error_alert;
struct tracker_reply_alert;
struct tracker_warning_alert;
struct fastresume_rejected_alert;
struct torrent_status;
}
namespace BitTorrent
{
struct PeerAddress;
class Session;
class PeerInfo;
class TrackerEntry;
struct AddTorrentParams;
struct AddTorrentData
{
bool resumed;
// for both new and resumed torrents
QString name;
QString label;
QString savePath;
bool disableTempPath;
bool sequential;
bool hasSeedStatus;
bool skipChecking;
TriStateBool addForced;
TriStateBool addPaused;
// for new torrents
QVector<int> filePriorities;
// for resumed torrents
qreal ratioLimit;
};
struct TrackerInfo
{
QString lastMessage;
quint32 numPeers;
TrackerInfo();
};
class TorrentState
{
public:
enum
{
Unknown = -1,
ForcedDownloading,
Downloading,
DownloadingMetadata,
Allocating,
StalledDownloading,
ForcedUploading,
Uploading,
StalledUploading,
QueuedDownloading,
QueuedUploading,
CheckingUploading,
CheckingDownloading,
QueuedForChecking,
CheckingResumeData,
PausedDownloading,
PausedUploading,
MissingFiles,
Error
};
TorrentState(int value);
operator int() const;
QString toString() const;
private:
int m_value;
};
class TorrentHandle : public QObject
{
Q_DISABLE_COPY(TorrentHandle)
public:
static const qreal USE_GLOBAL_RATIO;
static const qreal NO_RATIO_LIMIT;
static const qreal MAX_RATIO;
TorrentHandle(Session *session, const libtorrent::torrent_handle &nativeHandle,
const AddTorrentData &data);
~TorrentHandle();
bool isValid() const;
InfoHash hash() const;
QString name() const;
QDateTime creationDate() const;
QString creator() const;
QString comment() const;
bool isPrivate() const;
qlonglong totalSize() const;
qlonglong wantedSize() const;
qlonglong completedSize() const;
qlonglong incompletedSize() const;
qlonglong pieceLength() const;
qlonglong wastedSize() const;
QString currentTracker() const;
// 1. savePath() - the path where all the files and subfolders of torrent are stored (as always).
// 2. rootPath() - absolute path of torrent file tree (save path + first item from 1st torrent file path).
// 3. contentPath() - absolute path of torrent content (root path for multifile torrents, absolute file path for singlefile torrents).
//
// These methods have 'actual' parameter (defaults to false) which allow to get actual or final path variant.
//
// Examples.
// Suppose we have three torrent with following structures and save path `/home/user/torrents`:
//
// Torrent A (multifile)
//
// torrentA/
// subdir1/
// subdir2/
// file1
// file2
// file3
// file4
//
//
// Torrent B (singlefile)
//
// torrentB/
// subdir1/
// file1
//
//
// Torrent C (singlefile)
//
// file1
//
//
// Results:
// | | rootPath | contentPath |
// |---|------------------------------|--------------------------------------------|
// | A | /home/user/torrents/torrentA | /home/user/torrents/torrentA |
// | B | /home/user/torrents/torrentB | /home/user/torrents/torrentB/subdir1/file1 |
// | C | /home/user/torrents/file1 | /home/user/torrents/file1 |
QString savePath(bool actual = false) const;
QString rootPath(bool actual = false) const;
QString contentPath(bool actual = false) const;
int filesCount() const;
int piecesCount() const;
int piecesHave() const;
qreal progress() const;
QString label() const;
QDateTime addedTime() const;
qreal ratioLimit() const;
QString filePath(int index) const;
QString fileName(int index) const;
qlonglong fileSize(int index) const;
QStringList absoluteFilePaths() const;
QStringList absoluteFilePathsUnwanted() const;
QPair<int, int> fileExtremityPieces(int index) const;
QVector<int> filePriorities() const;
TorrentInfo info() const;
bool isSeed() const;
bool isPaused() const;
bool isResumed() const;
bool isQueued() const;
bool isForced() const;
bool isChecking() const;
bool isDownloading() const;
bool isUploading() const;
bool isCompleted() const;
bool isActive() const;
bool isInactive() const;
bool isErrored() const;
bool isSequentialDownload() const;
bool hasFirstLastPiecePriority() const;
TorrentState state() const;
bool hasMetadata() const;
bool hasMissingFiles() const;
bool hasError() const;
bool hasFilteredPieces() const;
int queuePosition() const;
QList<TrackerEntry> trackers() const;
QHash<QString, TrackerInfo> trackerInfos() const;
QList<QUrl> urlSeeds() const;
QString error() const;
qlonglong totalDownload() const;
qlonglong totalUpload() const;
int activeTime() const;
int finishedTime() const;
int seedingTime() const;
qulonglong eta() const;
QVector<qreal> filesProgress() const;
int seedsCount() const;
int peersCount() const;
int leechsCount() const;
int totalSeedsCount() const;
int totalPeersCount() const;
int totalLeechersCount() const;
int completeCount() const;
int incompleteCount() const;
QDateTime lastSeenComplete() const;
QDateTime completedTime() const;
int timeSinceUpload() const;
int timeSinceDownload() const;
int timeSinceActivity() const;
int downloadLimit() const;
int uploadLimit() const;
bool superSeeding() const;
QList<PeerInfo> peers() const;
QBitArray pieces() const;
QBitArray downloadingPieces() const;
QVector<int> pieceAvailability() const;
qreal distributedCopies() const;
qreal maxRatio(bool *usesGlobalRatio = 0) const;
qreal realRatio() const;
int uploadPayloadRate() const;
int downloadPayloadRate() const;
qlonglong totalPayloadUpload() const;
qlonglong totalPayloadDownload() const;
int connectionsCount() const;
int connectionsLimit() const;
qlonglong nextAnnounce() const;
void setName(const QString &name);
void setLabel(const QString &label);
void setSequentialDownload(bool b);
void toggleSequentialDownload();
void setFirstLastPiecePriority(bool b);
void toggleFirstLastPiecePriority();
void pause();
void resume(bool forced = false);
void move(QString path);
void forceReannounce(int index = -1);
void forceDHTAnnounce();
void forceRecheck();
void setTrackerLogin(const QString &username, const QString &password);
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 setUploadLimit(int limit);
void setDownloadLimit(int limit);
void setSuperSeeding(bool enable);
void flushCache();
void addTrackers(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);
QString toMagnetUri() const;
bool needSaveResumeData() const;
// Session interface
libtorrent::torrent_handle nativeHandle() const;
void handleAlert(libtorrent::alert *a);
void handleStateUpdate(const libtorrent::torrent_status &nativeStatus);
void handleTempPathChanged();
void handleAppendExtensionToggled();
void saveResumeData();
private:
typedef boost::function<void ()> EventTrigger;
void initialize();
void updateStatus();
void updateStatus(const libtorrent::torrent_status &nativeStatus);
void updateState();
void updateTorrentInfo();
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);
bool isMoveInProgress() const;
bool useTempPath() const;
QString nativeActualSavePath() const;
void adjustActualSavePath();
void adjustActualSavePath_impl();
void moveStorage(const QString &newPath);
void appendExtensionsToIncompleteFiles();
void removeExtensionsFromIncompleteFiles();
bool addTracker(const TrackerEntry &tracker);
bool addUrlSeed(const QUrl &urlSeed);
bool removeUrlSeed(const QUrl &urlSeed);
Session *const m_session;
libtorrent::torrent_handle m_nativeHandle;
libtorrent::torrent_status m_nativeStatus;
TorrentState m_state;
TorrentInfo m_torrentInfo;
SpeedMonitor m_speedMonitor;
InfoHash m_hash;
QString m_oldPath;
QString m_newPath;
// m_queuedPath is where files should be moved to,
// when current moving is completed
QString m_queuedPath;
// m_moveFinishedTriggers is activated only when the following conditions are met:
// all file rename jobs complete, all file move jobs complete
QQueue<EventTrigger> m_moveFinishedTriggers;
int m_renameCount;
// Persistent data
QString m_name;
QString m_savePath;
QString m_label;
bool m_hasSeedStatus;
qreal m_ratioLimit;
bool m_tempPathDisabled;
bool m_hasMissingFiles;
bool m_pauseAfterRecheck;
bool m_needSaveResumeData;
QHash<QString, TrackerInfo> m_trackerInfos;
};
}
#endif // BITTORRENT_TORRENTHANDLE_H

View File

@@ -0,0 +1,223 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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 <QString>
#include <QList>
#include <QUrl>
#include <QDateTime>
#include <libtorrent/error_code.hpp>
#include "core/utils/misc.h"
#include "core/utils/fs.h"
#include "core/utils/string.h"
#include "infohash.h"
#include "trackerentry.h"
#include "torrentinfo.h"
namespace libt = libtorrent;
using namespace BitTorrent;
TorrentInfo::TorrentInfo(boost::intrusive_ptr<const libt::torrent_info> nativeInfo)
: m_nativeInfo(const_cast<libt::torrent_info *>(nativeInfo.get()))
{
}
TorrentInfo::TorrentInfo(const TorrentInfo &other)
: m_nativeInfo(other.m_nativeInfo)
{
}
TorrentInfo &TorrentInfo::operator=(const TorrentInfo &other)
{
m_nativeInfo = other.m_nativeInfo;
return *this;
}
TorrentInfo TorrentInfo::loadFromFile(const QString &path, QString &error)
{
error.clear();
libt::error_code ec;
TorrentInfo info(new libt::torrent_info(Utils::String::toStdString(Utils::Fs::toNativePath(path)), ec));
if (ec) {
error = QString::fromUtf8(ec.message().c_str());
qDebug("Cannot load .torrent file: %s", qPrintable(error));
}
return info;
}
TorrentInfo TorrentInfo::loadFromFile(const QString &path)
{
QString error;
return loadFromFile(path, error);
}
bool TorrentInfo::isValid() const
{
return (m_nativeInfo && m_nativeInfo->is_valid() && (m_nativeInfo->num_files() > 0));
}
InfoHash TorrentInfo::hash() const
{
if (!isValid()) return InfoHash();
return m_nativeInfo->info_hash();
}
QString TorrentInfo::name() const
{
if (!isValid()) return QString();
return Utils::String::fromStdString(m_nativeInfo->name());
}
QDateTime TorrentInfo::creationDate() const
{
if (!isValid()) return QDateTime();
boost::optional<time_t> t = m_nativeInfo->creation_date();
return t ? QDateTime::fromTime_t(*t) : QDateTime();
}
QString TorrentInfo::creator() const
{
if (!isValid()) return QString();
return Utils::String::fromStdString(m_nativeInfo->creator());
}
QString TorrentInfo::comment() const
{
if (!isValid()) return QString();
return Utils::String::fromStdString(m_nativeInfo->comment());
}
bool TorrentInfo::isPrivate() const
{
if (!isValid()) return false;
return m_nativeInfo->priv();
}
qlonglong TorrentInfo::totalSize() const
{
if (!isValid()) return -1;
return m_nativeInfo->total_size();
}
int TorrentInfo::filesCount() const
{
if (!isValid()) return -1;
return m_nativeInfo->num_files();
}
int TorrentInfo::pieceLength() const
{
if (!isValid()) return -1;
return m_nativeInfo->piece_length();
}
int TorrentInfo::piecesCount() const
{
if (!isValid()) return -1;
return m_nativeInfo->num_pieces();
}
QString TorrentInfo::filePath(int index) const
{
if (!isValid()) return QString();
return Utils::Fs::fromNativePath(Utils::String::fromStdString(m_nativeInfo->files().file_path(index)));
}
QStringList TorrentInfo::filePaths() const
{
QStringList list;
for (int i = 0; i < filesCount(); ++i)
list << filePath(i);
return list;
}
QString TorrentInfo::fileName(int index) const
{
return Utils::Fs::fileName(filePath(index));
}
QString TorrentInfo::origFilePath(int index) const
{
if (!isValid()) return QString();
return Utils::Fs::fromNativePath(Utils::String::fromStdString(m_nativeInfo->orig_files().file_path(index)));
}
qlonglong TorrentInfo::fileSize(int index) const
{
if (!isValid()) return -1;
return m_nativeInfo->files().file_size(index);
}
qlonglong TorrentInfo::fileOffset(int index) const
{
if (!isValid()) return -1;
return m_nativeInfo->file_at(index).offset;
}
QList<TrackerEntry> TorrentInfo::trackers() const
{
if (!isValid()) return QList<TrackerEntry>();
QList<TrackerEntry> trackers;
foreach (const libt::announce_entry &tracker, m_nativeInfo->trackers())
trackers.append(tracker);
return trackers;
}
QList<QUrl> TorrentInfo::urlSeeds() const
{
if (!isValid()) return QList<QUrl>();
QList<QUrl> urlSeeds;
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()));
return urlSeeds;
}
QByteArray TorrentInfo::metadata() const
{
if (!isValid()) return QByteArray();
return QByteArray(m_nativeInfo->metadata().get(), m_nativeInfo->metadata_size());
}
void TorrentInfo::renameFile(uint index, const QString &newPath)
{
if (!isValid()) return;
m_nativeInfo->rename_file(index, Utils::String::toStdString(newPath));
}
boost::intrusive_ptr<libtorrent::torrent_info> TorrentInfo::nativeInfo() const
{
return m_nativeInfo;
}

View File

@@ -0,0 +1,87 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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 BITTORRENT_TORRENTINFO_H
#define BITTORRENT_TORRENTINFO_H
#include <QtGlobal>
#include <libtorrent/torrent_info.hpp>
class QString;
class QUrl;
class QDateTime;
class QStringList;
class QByteArray;
template<typename T> class QList;
namespace BitTorrent
{
class InfoHash;
class TrackerEntry;
class TorrentInfo
{
public:
explicit TorrentInfo(boost::intrusive_ptr<const libtorrent::torrent_info> nativeInfo = boost::intrusive_ptr<const libtorrent::torrent_info>());
TorrentInfo(const TorrentInfo &other);
static TorrentInfo loadFromFile(const QString &path, QString &error);
static TorrentInfo loadFromFile(const QString &path);
TorrentInfo &operator=(const TorrentInfo &other);
bool isValid() const;
InfoHash hash() const;
QString name() const;
QDateTime creationDate() const;
QString creator() const;
QString comment() const;
bool isPrivate() const;
qlonglong totalSize() const;
int filesCount() const;
int pieceLength() const;
int piecesCount() const;
QString filePath(int index) const;
QStringList filePaths() const;
QString fileName(int index) const;
QString origFilePath(int index) const;
qlonglong fileSize(int index) const;
qlonglong fileOffset(int index) const;
QList<TrackerEntry> trackers() const;
QList<QUrl> urlSeeds() const;
QByteArray metadata() const;
void renameFile(uint index, const QString &newPath);
boost::intrusive_ptr<libtorrent::torrent_info> nativeInfo() const;
private:
boost::intrusive_ptr<libtorrent::torrent_info> m_nativeInfo;
};
}
#endif // BITTORRENT_TORRENTINFO_H

View File

@@ -31,59 +31,68 @@
#include <vector>
#include <libtorrent/bencode.hpp>
#include <libtorrent/entry.hpp>
#include "preferences.h"
#include "http/server.h"
#include "qtracker.h"
#include "core/preferences.h"
#include "core/http/server.h"
#include "core/utils/string.h"
#include "tracker.h"
// QPeer
bool QPeer::operator!=(const QPeer &other) const
// static limits
static const int MAX_TORRENTS = 100;
static const int MAX_PEERS_PER_TORRENT = 1000;
static const int ANNOUNCE_INTERVAL = 1800; // 30min
using namespace BitTorrent;
// Peer
bool Peer::operator!=(const Peer &other) const
{
return qhash() != other.qhash();
return uid() != other.uid();
}
bool QPeer::operator==(const QPeer &other) const
bool Peer::operator==(const Peer &other) const
{
return qhash() == other.qhash();
return uid() == other.uid();
}
QString QPeer::qhash() const
QString Peer::uid() const
{
return ip + ":" + QString::number(port);
}
libtorrent::entry QPeer::toEntry(bool no_peer_id) const
libtorrent::entry Peer::toEntry(bool noPeerId) const
{
libtorrent::entry::dictionary_type peer_map;
if (!no_peer_id)
peer_map["id"] = libtorrent::entry(peer_id.toStdString());
peer_map["ip"] = libtorrent::entry(ip.toStdString());
peer_map["port"] = libtorrent::entry(port);
libtorrent::entry::dictionary_type peerMap;
if (!noPeerId)
peerMap["id"] = libtorrent::entry(Utils::String::toStdString(peerId));
peerMap["ip"] = libtorrent::entry(Utils::String::toStdString(ip));
peerMap["port"] = libtorrent::entry(port);
return libtorrent::entry(peer_map);
return libtorrent::entry(peerMap);
}
// QTracker
// Tracker
QTracker::QTracker(QObject *parent)
Tracker::Tracker(QObject *parent)
: Http::ResponseBuilder(parent)
, m_server(new Http::Server(this, this))
{
}
QTracker::~QTracker()
Tracker::~Tracker()
{
if (m_server->isListening())
qDebug("Shutting down the embedded tracker...");
// TODO: Store the torrent list
}
bool QTracker::start()
bool Tracker::start()
{
const int listen_port = Preferences::instance()->getTrackerPort();
const int listenPort = Preferences::instance()->getTrackerPort();
if (m_server->isListening()) {
if (m_server->serverPort() == listen_port) {
if (m_server->serverPort() == listenPort) {
// Already listening on the right port, just return
return true;
}
@@ -93,21 +102,21 @@ bool QTracker::start()
qDebug("Starting the embedded tracker...");
// Listen on the predefined port
return m_server->listen(QHostAddress::Any, listen_port);
return m_server->listen(QHostAddress::Any, listenPort);
}
Http::Response QTracker::processRequest(const Http::Request &request, const Http::Environment &env)
Http::Response Tracker::processRequest(const Http::Request &request, const Http::Environment &env)
{
clear(); // clear response
//qDebug("QTracker received the following request:\n%s", qPrintable(parser.toString()));
//qDebug("Tracker received the following request:\n%s", qPrintable(parser.toString()));
// Is request a GET request?
if (request.method != "GET") {
qDebug("QTracker: Unsupported HTTP request: %s", qPrintable(request.method));
qDebug("Tracker: Unsupported HTTP request: %s", qPrintable(request.method));
status(100, "Invalid request type");
}
else if (!request.path.startsWith("/announce", Qt::CaseInsensitive)) {
qDebug("QTracker: Unrecognized path: %s", qPrintable(request.path));
qDebug("Tracker: Unrecognized path: %s", qPrintable(request.path));
status(100, "Invalid request type");
}
else {
@@ -120,85 +129,85 @@ Http::Response QTracker::processRequest(const Http::Request &request, const Http
return response();
}
void QTracker::respondToAnnounceRequest()
void Tracker::respondToAnnounceRequest()
{
const QStringMap &gets = m_request.gets;
TrackerAnnounceRequest annonce_req;
TrackerAnnounceRequest annonceReq;
// IP
annonce_req.peer.ip = m_env.clientAddress.toString();
annonceReq.peer.ip = m_env.clientAddress.toString();
// 1. Get info_hash
if (!gets.contains("info_hash")) {
qDebug("QTracker: Missing info_hash");
qDebug("Tracker: Missing info_hash");
status(101, "Missing info_hash");
return;
}
annonce_req.info_hash = gets.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("QTracker: Info_hash is not 20 byte long: %s (%d)", qPrintable(annonce_req.info_hash), annonce_req.info_hash.toLatin1().length());
qDebug("Tracker: Info_hash is not 20 byte long: %s (%d)", qPrintable(annonce_req.info_hash), annonce_req.info_hash.toLatin1().length());
status(150, "Invalid infohash");
return;
}*/
// 2. Get peer ID
if (!gets.contains("peer_id")) {
qDebug("QTracker: Missing peer_id");
qDebug("Tracker: Missing peer_id");
status(102, "Missing peer_id");
return;
}
annonce_req.peer.peer_id = gets.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("QTracker: peer_id is not 20 byte long: %s", qPrintable(annonce_req.peer.peer_id));
qDebug("Tracker: peer_id is not 20 byte long: %s", qPrintable(annonce_req.peer.peer_id));
status(151, "Invalid peerid");
return;
}*/
// 3. Get port
if (!gets.contains("port")) {
qDebug("QTracker: Missing port");
qDebug("Tracker: Missing port");
status(103, "Missing port");
return;
}
bool ok = false;
annonce_req.peer.port = gets.value("port").toInt(&ok);
if (!ok || annonce_req.peer.port < 1 || annonce_req.peer.port > 65535) {
qDebug("QTracker: Invalid port number (%d)", annonce_req.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
annonce_req.event = "";
annonceReq.event = "";
if (gets.contains("event")) {
annonce_req.event = gets.value("event");
qDebug("QTracker: event is %s", qPrintable(annonce_req.event));
annonceReq.event = gets.value("event");
qDebug("Tracker: event is %s", qPrintable(annonceReq.event));
}
// 5. Get numwant
annonce_req.numwant = 50;
annonceReq.numwant = 50;
if (gets.contains("numwant")) {
int tmp = gets.value("numwant").toInt();
if (tmp > 0) {
qDebug("QTracker: numwant = %d", tmp);
annonce_req.numwant = tmp;
qDebug("Tracker: numwant = %d", tmp);
annonceReq.numwant = tmp;
}
}
// 6. no_peer_id (extension)
annonce_req.no_peer_id = false;
annonceReq.noPeerId = false;
if (gets.contains("no_peer_id"))
annonce_req.no_peer_id = true;
annonceReq.noPeerId = true;
// 7. TODO: support "compact" extension
// Done parsing, now let's reply
if (m_torrents.contains(annonce_req.info_hash)) {
if (annonce_req.event == "stopped") {
qDebug("QTracker: Peer stopped downloading, deleting it from the list");
m_torrents[annonce_req.info_hash].remove(annonce_req.peer.qhash());
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;
}
}
@@ -210,36 +219,36 @@ void QTracker::respondToAnnounceRequest()
}
}
// Register the user
PeerList peers = m_torrents.value(annonce_req.info_hash);
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[annonce_req.peer.qhash()] = annonce_req.peer;
m_torrents[annonce_req.info_hash] = peers;
peers[annonceReq.peer.uid()] = annonceReq.peer;
m_torrents[annonceReq.infoHash] = peers;
// Reply
replyWithPeerList(annonce_req);
replyWithPeerList(annonceReq);
}
void QTracker::replyWithPeerList(const TrackerAnnounceRequest &annonce_req)
void Tracker::replyWithPeerList(const TrackerAnnounceRequest &annonceReq)
{
// Prepare the entry for bencoding
libtorrent::entry::dictionary_type reply_dict;
reply_dict["interval"] = libtorrent::entry(ANNOUNCE_INTERVAL);
QList<QPeer> peers = m_torrents.value(annonce_req.info_hash).values();
libtorrent::entry::list_type peer_list;
foreach (const QPeer &p, peers) {
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;
foreach (const Peer &p, peers) {
//if (p != annonce_req.peer)
peer_list.push_back(p.toEntry(annonce_req.no_peer_id));
peerList.push_back(p.toEntry(annonceReq.noPeerId));
}
reply_dict["peers"] = libtorrent::entry(peer_list);
libtorrent::entry reply_entry(reply_dict);
replyDict["peers"] = libtorrent::entry(peerList);
libtorrent::entry replyEntry(replyDict);
// bencode
std::vector<char> buf;
libtorrent::bencode(std::back_inserter(buf), reply_entry);
libtorrent::bencode(std::back_inserter(buf), replyEntry);
QByteArray reply(&buf[0], static_cast<int>(buf.size()));
qDebug("QTracker: reply with the following bencoded data:\n %s", reply.constData());
qDebug("Tracker: reply with the following bencoded data:\n %s", reply.constData());
// HTTP reply
print(reply, Http::CONTENT_TYPE_TXT);

View File

@@ -0,0 +1,103 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* 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
* 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.
*
* Contact : chris@qbittorrent.org
*/
#ifndef BITTORRENT_TRACKER_H
#define BITTORRENT_TRACKER_H
#include <QHash>
#include "core/http/types.h"
#include "core/http/responsebuilder.h"
#include "core/http/irequesthandler.h"
namespace libtorrent
{
class entry;
}
namespace Http
{
class Server;
}
namespace BitTorrent
{
struct Peer
{
QString ip;
QString peerId;
int port;
bool operator!=(const Peer &other) const;
bool operator==(const Peer &other) const;
QString uid() const;
libtorrent::entry toEntry(bool noPeerId) const;
};
struct TrackerAnnounceRequest
{
QString infoHash;
QString event;
int numwant;
Peer peer;
// Extensions
bool noPeerId;
};
typedef QHash<QString, Peer> PeerList;
typedef QHash<QString, PeerList> TorrentList;
/* Basic Bittorrent tracker implementation in Qt */
/* Following http://wiki.theory.org/BitTorrent_Tracker_Protocol */
class Tracker : public Http::ResponseBuilder, public Http::IRequestHandler
{
Q_OBJECT
Q_DISABLE_COPY(Tracker)
public:
explicit Tracker(QObject *parent = 0);
~Tracker();
bool start();
Http::Response processRequest(const Http::Request &request, const Http::Environment &env);
private:
void respondToAnnounceRequest();
void replyWithPeerList(const TrackerAnnounceRequest &annonceReq);
Http::Server *m_server;
TorrentList m_torrents;
Http::Request m_request;
Http::Environment m_env;
};
}
#endif // BITTORRENT_TRACKER_H

View File

@@ -0,0 +1,95 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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 <QString>
#include "core/utils/misc.h"
#include "core/utils/string.h"
#include "trackerentry.h"
using namespace BitTorrent;
TrackerEntry::TrackerEntry(const QString &url)
: m_nativeEntry(libtorrent::announce_entry(Utils::String::toStdString(url)))
{
}
TrackerEntry::TrackerEntry(const libtorrent::announce_entry &nativeEntry)
: m_nativeEntry(nativeEntry)
{
}
TrackerEntry::TrackerEntry(const TrackerEntry &other)
: m_nativeEntry(other.m_nativeEntry)
{
}
QString TrackerEntry::url() const
{
return Utils::String::fromStdString(m_nativeEntry.url);
}
int TrackerEntry::tier() const
{
return m_nativeEntry.tier;
}
TrackerEntry::Status TrackerEntry::status() const
{
// libtorrent::announce_entry::is_working() returns
// true when the tracker hasn't been tried yet.
if (m_nativeEntry.verified && m_nativeEntry.is_working())
return Working;
else if ((m_nativeEntry.fails == 0) && m_nativeEntry.updating)
return Updating;
else if (m_nativeEntry.fails == 0)
return NotContacted;
else
return NotWorking;
}
void TrackerEntry::setTier(int value)
{
m_nativeEntry.tier = value;
}
TrackerEntry &TrackerEntry::operator=(const TrackerEntry &other)
{
this->m_nativeEntry = other.m_nativeEntry;
return *this;
}
bool TrackerEntry::operator==(const TrackerEntry &other)
{
return (QUrl(url()) == QUrl(other.url()));
}
libtorrent::announce_entry TrackerEntry::nativeEntry() const
{
return m_nativeEntry;
}

View File

@@ -0,0 +1,68 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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 BITTORRENT_TRACKERENTRY_H
#define BITTORRENT_TRACKERENTRY_H
#include <libtorrent/torrent_info.hpp>
class QString;
namespace BitTorrent
{
class TrackerEntry
{
public:
enum Status
{
NotContacted,
Working,
Updating,
NotWorking
};
TrackerEntry(const QString &url);
TrackerEntry(const libtorrent::announce_entry &nativeEntry);
TrackerEntry(const TrackerEntry &other);
QString url() const;
int tier() const;
Status status() const;
void setTier(int value);
TrackerEntry &operator=(const TrackerEntry &other);
bool operator==(const TrackerEntry &other);
libtorrent::announce_entry nativeEntry() const;
private:
libtorrent::announce_entry m_nativeEntry;
};
}
#endif // BITTORRENT_TRACKERENTRY_H

View File

@@ -1,22 +1,11 @@
INCLUDEPATH += $$PWD
unix:!macx:dbus: include(qtnotify/qtnotify.pri)
include(qtlibtorrent/qtlibtorrent.pri)
HEADERS += \
$$PWD/misc.h \
$$PWD/fs_utils.h \
$$PWD/downloadthread.h \
$$PWD/torrentpersistentdata.h \
$$PWD/types.h \
$$PWD/tristatebool.h \
$$PWD/filesystemwatcher.h \
$$PWD/scannedfoldersmodel.h \
$$PWD/qinisettings.h \
$$PWD/smtp.h \
$$PWD/dnsupdater.h \
$$PWD/logger.h \
$$PWD/preferences.h \
$$PWD/qtracker.h \
$$PWD/iconprovider.h \
$$PWD/http/irequesthandler.h \
$$PWD/http/connection.h \
$$PWD/http/requestparser.h \
@@ -24,21 +13,74 @@ HEADERS += \
$$PWD/http/server.h \
$$PWD/http/types.h \
$$PWD/http/responsebuilder.h \
$$PWD/unicodestrings.h
$$PWD/net/dnsupdater.h \
$$PWD/net/downloadmanager.h \
$$PWD/net/downloadhandler.h \
$$PWD/net/geoipmanager.h \
$$PWD/net/portforwarder.h \
$$PWD/net/reverseresolution.h \
$$PWD/net/smtp.h \
$$PWD/net/private/geoipdatabase.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/utils/fs.h \
$$PWD/utils/gzip.h \
$$PWD/utils/misc.h \
$$PWD/utils/string.h \
$$PWD/unicodestrings.h \
$$PWD/torrentfilter.h \
$$PWD/scanfoldersmodel.h
SOURCES += \
$$PWD/downloadthread.cpp \
$$PWD/scannedfoldersmodel.cpp \
$$PWD/torrentpersistentdata.cpp \
$$PWD/misc.cpp \
$$PWD/fs_utils.cpp \
$$PWD/smtp.cpp \
$$PWD/dnsupdater.cpp \
$$PWD/tristatebool.cpp \
$$PWD/filesystemwatcher.cpp \
$$PWD/logger.cpp \
$$PWD/preferences.cpp \
$$PWD/qtracker.cpp \
$$PWD/iconprovider.cpp \
$$PWD/http/connection.cpp \
$$PWD/http/requestparser.cpp \
$$PWD/http/responsegenerator.cpp \
$$PWD/http/server.cpp \
$$PWD/http/responsebuilder.cpp
$$PWD/http/responsebuilder.cpp \
$$PWD/net/dnsupdater.cpp \
$$PWD/net/downloadmanager.cpp \
$$PWD/net/downloadhandler.cpp \
$$PWD/net/geoipmanager.cpp \
$$PWD/net/portforwarder.cpp \
$$PWD/net/reverseresolution.cpp \
$$PWD/net/smtp.cpp \
$$PWD/net/private/geoipdatabase.cpp \
$$PWD/bittorrent/infohash.cpp \
$$PWD/bittorrent/session.cpp \
$$PWD/bittorrent/sessionstatus.cpp \
$$PWD/bittorrent/cachestatus.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/utils/fs.cpp \
$$PWD/utils/gzip.cpp \
$$PWD/utils/misc.cpp \
$$PWD/utils/string.cpp \
$$PWD/torrentfilter.cpp \
$$PWD/scanfoldersmodel.cpp

View File

@@ -1,297 +0,0 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2011 Christophe Dumez
*
* 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.
*
* Contact : chris@qbittorrent.org
*/
#include <QNetworkAccessManager>
#include <QDebug>
#include <QRegExp>
#include <QStringList>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
#include <QUrlQuery>
#endif
#include "dnsupdater.h"
#include "logger.h"
DNSUpdater::DNSUpdater(QObject *parent) :
QObject(parent), m_state(OK), m_service(DNS::NONE)
{
updateCredentials();
// Load saved settings from previous session
const Preferences* const pref = Preferences::instance();
m_lastIPCheckTime = pref->getDNSLastUpd();
m_lastIP = QHostAddress(pref->getDNSLastIP());
// Start IP checking timer
m_ipCheckTimer.setInterval(IP_CHECK_INTERVAL_MS);
connect(&m_ipCheckTimer, SIGNAL(timeout()), SLOT(checkPublicIP()));
m_ipCheckTimer.start();
// Check lastUpdate to avoid flooding
if (!m_lastIPCheckTime.isValid() ||
m_lastIPCheckTime.secsTo(QDateTime::currentDateTime())*1000 > IP_CHECK_INTERVAL_MS) {
checkPublicIP();
}
}
DNSUpdater::~DNSUpdater() {
// Save lastupdate time and last ip
Preferences* const pref = Preferences::instance();
pref->setDNSLastUpd(m_lastIPCheckTime);
pref->setDNSLastIP(m_lastIP.toString());
}
void DNSUpdater::checkPublicIP()
{
Q_ASSERT(m_state == OK);
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)),
SLOT(ipRequestFinished(QNetworkReply*)));
m_lastIPCheckTime = QDateTime::currentDateTime();
QNetworkRequest request;
request.setUrl(QUrl("http://checkip.dyndns.org"));
request.setRawHeader("User-Agent", "qBittorrent/" VERSION);
manager->get(request);
}
void DNSUpdater::ipRequestFinished(QNetworkReply *reply)
{
qDebug() << Q_FUNC_INFO;
if (reply->error()) {
// Error
qWarning() << Q_FUNC_INFO << "Error:" << reply->errorString();
} else {
// Parse response
QRegExp ipregex("Current IP Address:\\s+([^<]+)</body>");
QString ret = reply->readAll();
if (ipregex.indexIn(ret) >= 0) {
QString ip_str = ipregex.cap(1);
qDebug() << Q_FUNC_INFO << "Regular expression captured the following IP:" << ip_str;
QHostAddress new_ip(ip_str);
if (!new_ip.isNull()) {
if (m_lastIP != new_ip) {
qDebug() << Q_FUNC_INFO << "The IP address changed, report the change to DynDNS...";
qDebug() << m_lastIP.toString() << "->" << new_ip.toString();
m_lastIP = new_ip;
updateDNSService();
}
} else {
qWarning() << Q_FUNC_INFO << "Failed to construct a QHostAddress from the IP string";
}
} else {
qWarning() << Q_FUNC_INFO << "Regular expression failed ot capture the IP address";
}
}
// Clean up
reply->deleteLater();
sender()->deleteLater();
}
void DNSUpdater::updateDNSService()
{
qDebug() << Q_FUNC_INFO;
// Prepare request
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)),
SLOT(ipUpdateFinished(QNetworkReply*)));
m_lastIPCheckTime = QDateTime::currentDateTime();
QNetworkRequest request;
request.setUrl(getUpdateUrl());
request.setRawHeader("User-Agent", "qBittorrent/" VERSION);
manager->get(request);
}
QUrl DNSUpdater::getUpdateUrl() const
{
QUrl url;
#ifdef QT_NO_OPENSSL
url.setScheme("http");
#else
url.setScheme("https");
#endif
url.setUserName(m_username);
url.setPassword(m_password);
Q_ASSERT(!m_lastIP.isNull());
// Service specific
switch(m_service) {
case DNS::DYNDNS:
url.setHost("members.dyndns.org");
break;
case DNS::NOIP:
url.setHost("dynupdate.no-ip.com");
break;
default:
qWarning() << "Unrecognized Dynamic DNS service!";
Q_ASSERT(0);
}
url.setPath("/nic/update");
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
url.addQueryItem("hostname", m_domain);
url.addQueryItem("myip", m_lastIP.toString());
#else
QUrlQuery urlQuery(url);
urlQuery.addQueryItem("hostname", m_domain);
urlQuery.addQueryItem("myip", m_lastIP.toString());
url.setQuery(urlQuery);
#endif
Q_ASSERT(url.isValid());
qDebug() << Q_FUNC_INFO << url.toString();
return url;
}
void DNSUpdater::ipUpdateFinished(QNetworkReply *reply)
{
if (reply->error()) {
// Error
qWarning() << Q_FUNC_INFO << "Error:" << reply->errorString();
} else {
// Pase reply
processIPUpdateReply(reply->readAll());
}
// Clean up
reply->deleteLater();
sender()->deleteLater();
}
void DNSUpdater::processIPUpdateReply(const QString &reply)
{
Logger* const logger = Logger::instance();
qDebug() << Q_FUNC_INFO << reply;
QString code = reply.split(" ").first();
qDebug() << Q_FUNC_INFO << "Code:" << code;
if (code == "good" || code == "nochg") {
logger->addMessage(tr("Your dynamic DNS was successfully updated."), Log::INFO);
return;
}
if (code == "911" || code == "dnserr") {
logger->addMessage(tr("Dynamic DNS error: The service is temporarily unavailable, it will be retried in 30 minutes."), Log::CRITICAL);
m_lastIP.clear();
// It will retry in 30 minutes because the timer was not stopped
return;
}
// Everything bellow is an error, stop updating until the user updates something
m_ipCheckTimer.stop();
m_lastIP.clear();
if (code == "nohost") {
logger->addMessage(tr("Dynamic DNS error: hostname supplied does not exist under specified account."), Log::CRITICAL);
m_state = INVALID_CREDS;
return;
}
if (code == "badauth") {
logger->addMessage(tr("Dynamic DNS error: Invalid username/password."), Log::CRITICAL);
m_state = INVALID_CREDS;
return;
}
if (code == "badagent") {
logger->addMessage(tr("Dynamic DNS error: qBittorrent was blacklisted by the service, please report a bug at http://bugs.qbittorrent.org."),
Log::CRITICAL);
m_state = FATAL;
return;
}
if (code == "!donator") {
logger->addMessage(tr("Dynamic DNS error: %1 was returned by the service, please report a bug at http://bugs.qbittorrent.org.").arg("!donator"),
Log::CRITICAL);
m_state = FATAL;
return;
}
if (code == "abuse") {
logger->addMessage(tr("Dynamic DNS error: Your username was blocked due to abuse."), Log::CRITICAL);
m_state = FATAL;
return;
}
}
void DNSUpdater::updateCredentials()
{
if (m_state == FATAL) return;
Preferences* const pref = Preferences::instance();
Logger* const logger = Logger::instance();
bool change = false;
// Get DNS service information
if (m_service != pref->getDynDNSService()) {
m_service = pref->getDynDNSService();
change = true;
}
if (m_domain != pref->getDynDomainName()) {
m_domain = pref->getDynDomainName();
QRegExp domain_regex("^(?:(?!\\d|-)[a-zA-Z0-9\\-]{1,63}\\.)+[a-zA-Z]{2,}$");
if (domain_regex.indexIn(m_domain) < 0) {
logger->addMessage(tr("Dynamic DNS error: supplied domain name is invalid."), Log::CRITICAL);
m_lastIP.clear();
m_ipCheckTimer.stop();
m_state = INVALID_CREDS;
return;
}
change = true;
}
if (m_username != pref->getDynDNSUsername()) {
m_username = pref->getDynDNSUsername();
if (m_username.length() < 4) {
logger->addMessage(tr("Dynamic DNS error: supplied username is too short."), Log::CRITICAL);
m_lastIP.clear();
m_ipCheckTimer.stop();
m_state = INVALID_CREDS;
return;
}
change = true;
}
if (m_password != pref->getDynDNSPassword()) {
m_password = pref->getDynDNSPassword();
if (m_password.length() < 4) {
logger->addMessage(tr("Dynamic DNS error: supplied password is too short."), Log::CRITICAL);
m_lastIP.clear();
m_ipCheckTimer.stop();
m_state = INVALID_CREDS;
return;
}
change = true;
}
if (m_state == INVALID_CREDS && change) {
m_state = OK; // Try again
m_ipCheckTimer.start();
checkPublicIP();
}
}
QUrl DNSUpdater::getRegistrationUrl(int service)
{
switch(service) {
case DNS::DYNDNS:
return QUrl("https://www.dyndns.com/account/services/hosts/add.html");
case DNS::NOIP:
return QUrl("http://www.no-ip.com/services/managed_dns/free_dynamic_dns.html");
default:
Q_ASSERT(0);
}
return QUrl();
}

View File

@@ -1,311 +0,0 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* 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
* 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.
*
* Contact : chris@qbittorrent.org
*/
#include <QTemporaryFile>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkProxy>
#include <QNetworkCookieJar>
#include <QDebug>
#include "downloadthread.h"
#include "preferences.h"
#include "qinisettings.h"
#include "fs_utils.h"
#include <zlib.h>
/** Download Thread **/
DownloadThread::DownloadThread(QObject* parent) : QObject(parent) {
connect(&m_networkManager, SIGNAL(finished (QNetworkReply*)), this, SLOT(processDlFinished(QNetworkReply*)));
#ifndef QT_NO_OPENSSL
connect(&m_networkManager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), this, SLOT(ignoreSslErrors(QNetworkReply*,QList<QSslError>)));
#endif
}
QByteArray DownloadThread::gUncompress(Bytef *inData, size_t len) {
if (len <= 4) {
qWarning("gUncompress: Input data is truncated");
return QByteArray();
}
QByteArray result;
z_stream strm;
static const int CHUNK_SIZE = 1024;
char out[CHUNK_SIZE];
/* allocate inflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = len;
strm.next_in = inData;
const int windowBits = 15;
const int ENABLE_ZLIB_GZIP = 32;
int ret = inflateInit2(&strm, windowBits|ENABLE_ZLIB_GZIP ); // gzip decoding
if (ret != Z_OK)
return QByteArray();
// run inflate()
do {
strm.avail_out = CHUNK_SIZE;
strm.next_out = reinterpret_cast<unsigned char*>(out);
ret = inflate(&strm, Z_NO_FLUSH);
Q_ASSERT(ret != Z_STREAM_ERROR); // state not clobbered
switch (ret) {
case Z_NEED_DICT:
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void) inflateEnd(&strm);
return QByteArray();
}
result.append(out, CHUNK_SIZE - strm.avail_out);
} while (!strm.avail_out);
// clean up and return
inflateEnd(&strm);
return result;
}
void DownloadThread::processDlFinished(QNetworkReply* reply) {
QString url = reply->url().toString();
qDebug("Download finished: %s", qPrintable(url));
// Check if the request was successful
if (reply->error() != QNetworkReply::NoError) {
// Failure
qDebug("Download failure (%s), reason: %s", qPrintable(url), qPrintable(errorCodeToString(reply->error())));
emit downloadFailure(url, errorCodeToString(reply->error()));
reply->deleteLater();
return;
}
// Check if the server ask us to redirect somewhere lese
const QVariant redirection = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (redirection.isValid()) {
// We should redirect
QUrl newUrl = redirection.toUrl();
// Resolve relative urls
if (newUrl.isRelative())
newUrl = reply->url().resolved(newUrl);
const QString newUrlString = newUrl.toString();
qDebug("Redirecting from %s to %s", qPrintable(url), qPrintable(newUrlString));
// Redirect to magnet workaround
if (newUrlString.startsWith("magnet:", Qt::CaseInsensitive)) {
qDebug("Magnet redirect detected.");
reply->abort();
emit magnetRedirect(newUrlString, url);
reply->deleteLater();
return;
}
m_redirectMapping.insert(newUrlString, url);
// redirecting with first cookies
downloadUrl(newUrlString, m_networkManager.cookieJar()->cookiesForUrl(url));
reply->deleteLater();
return;
}
// Checking if it was redirected, restoring initial URL
if (m_redirectMapping.contains(url)) {
url = m_redirectMapping.take(url);
}
// Success
QTemporaryFile *tmpfile = new QTemporaryFile;
if (tmpfile->open()) {
tmpfile->setAutoRemove(false);
QString filePath = tmpfile->fileName();
qDebug("Temporary filename is: %s", qPrintable(filePath));
if (reply->isOpen() || reply->open(QIODevice::ReadOnly)) {
QByteArray replyData = reply->readAll();
if (reply->rawHeader("Content-Encoding") == "gzip") {
// uncompress gzip reply
replyData = gUncompress(reinterpret_cast<unsigned char*>(replyData.data()), replyData.length());
}
tmpfile->write(replyData);
tmpfile->close();
// XXX: tmpfile needs to be deleted on Windows before using the file
// or it will complain that the file is used by another process.
delete tmpfile;
// Send finished signal
emit downloadFinished(url, filePath);
} else {
delete tmpfile;
fsutils::forceRemove(filePath);
// Error when reading the request
emit downloadFailure(url, tr("I/O Error"));
}
} else {
delete tmpfile;
emit downloadFailure(url, tr("I/O Error"));
}
// Clean up
reply->deleteLater();
}
void DownloadThread::downloadTorrentUrl(const QString &url, const QList<QNetworkCookie>& cookies)
{
// Process request
QNetworkReply *reply = downloadUrl(url, cookies);
connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(checkDownloadSize(qint64,qint64)));
}
QNetworkReply* DownloadThread::downloadUrl(const QString &url, const QList<QNetworkCookie>& cookies) {
// Update proxy settings
applyProxySettings();
// Set cookies
if (!cookies.empty()) {
qDebug("Setting %d cookies for url: %s", cookies.size(), qPrintable(url));
m_networkManager.cookieJar()->setCookiesFromUrl(cookies, url);
}
// Process download request
qDebug("url is %s", qPrintable(url));
const QUrl qurl = QUrl::fromEncoded(url.toUtf8());
QNetworkRequest request(qurl);
// Spoof Firefox 38 user agent to avoid web server banning
request.setRawHeader("User-Agent", "Mozilla/5.0 (X11; Linux i686; rv:38.0) Gecko/20100101 Firefox/38.0");
qDebug("Downloading %s...", request.url().toEncoded().data());
qDebug("%d cookies for this URL", m_networkManager.cookieJar()->cookiesForUrl(url).size());
for (int i=0; i<m_networkManager.cookieJar()->cookiesForUrl(url).size(); ++i) {
qDebug("%s=%s", m_networkManager.cookieJar()->cookiesForUrl(url).at(i).name().data(), m_networkManager.cookieJar()->cookiesForUrl(url).at(i).value().data());
qDebug("Domain: %s, Path: %s", qPrintable(m_networkManager.cookieJar()->cookiesForUrl(url).at(i).domain()), qPrintable(m_networkManager.cookieJar()->cookiesForUrl(url).at(i).path()));
}
// accept gzip
request.setRawHeader("Accept-Encoding", "gzip");
return m_networkManager.get(request);
}
void DownloadThread::checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal) {
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
if (!reply) return;
if (bytesTotal > 0) {
// Total number of bytes is available
if (bytesTotal > 1048576*10) {
// More than 10MB, this is probably not a torrent file, aborting...
reply->abort();
reply->deleteLater();
} else {
disconnect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(checkDownloadSize(qint64,qint64)));
}
} else {
if (bytesReceived > 1048576*10) {
// More than 10MB, this is probably not a torrent file, aborting...
reply->abort();
reply->deleteLater();
}
}
}
void DownloadThread::applyProxySettings() {
QNetworkProxy proxy;
const Preferences* const pref = Preferences::instance();
if (pref->isProxyEnabled()) {
// Proxy enabled
proxy.setHostName(pref->getProxyIp());
proxy.setPort(pref->getProxyPort());
// Default proxy type is HTTP, we must change if it is SOCKS5
const int proxy_type = pref->getProxyType();
if (proxy_type == Proxy::SOCKS5 || proxy_type == Proxy::SOCKS5_PW) {
qDebug() << Q_FUNC_INFO << "using SOCKS proxy";
proxy.setType(QNetworkProxy::Socks5Proxy);
} else {
qDebug() << Q_FUNC_INFO << "using HTTP proxy";
proxy.setType(QNetworkProxy::HttpProxy);
}
// Authentication?
if (pref->isProxyAuthEnabled()) {
qDebug("Proxy requires authentication, authenticating");
proxy.setUser(pref->getProxyUsername());
proxy.setPassword(pref->getProxyPassword());
}
} else {
proxy.setType(QNetworkProxy::NoProxy);
}
m_networkManager.setProxy(proxy);
}
QString DownloadThread::errorCodeToString(QNetworkReply::NetworkError status) {
switch(status) {
case QNetworkReply::HostNotFoundError:
return tr("The remote host name was not found (invalid hostname)");
case QNetworkReply::OperationCanceledError:
return tr("The operation was canceled");
case QNetworkReply::RemoteHostClosedError:
return tr("The remote server closed the connection prematurely, before the entire reply was received and processed");
case QNetworkReply::TimeoutError:
return tr("The connection to the remote server timed out");
case QNetworkReply::SslHandshakeFailedError:
return tr("SSL/TLS handshake failed");
case QNetworkReply::ConnectionRefusedError:
return tr("The remote server refused the connection");
case QNetworkReply::ProxyConnectionRefusedError:
return tr("The connection to the proxy server was refused");
case QNetworkReply::ProxyConnectionClosedError:
return tr("The proxy server closed the connection prematurely");
case QNetworkReply::ProxyNotFoundError:
return tr("The proxy host name was not found");
case QNetworkReply::ProxyTimeoutError:
return tr("The connection to the proxy timed out or the proxy did not reply in time to the request sent");
case QNetworkReply::ProxyAuthenticationRequiredError:
return tr("The proxy requires authentication in order to honour the request but did not accept any credentials offered");
case QNetworkReply::ContentAccessDenied:
return tr("The access to the remote content was denied (401)");
case QNetworkReply::ContentOperationNotPermittedError:
return tr("The operation requested on the remote content is not permitted");
case QNetworkReply::ContentNotFoundError:
return tr("The remote content was not found at the server (404)");
case QNetworkReply::AuthenticationRequiredError:
return tr("The remote server requires authentication to serve the content but the credentials provided were not accepted");
case QNetworkReply::ProtocolUnknownError:
return tr("The Network Access API cannot honor the request because the protocol is not known");
case QNetworkReply::ProtocolInvalidOperationError:
return tr("The requested operation is invalid for this protocol");
case QNetworkReply::UnknownNetworkError:
return tr("An unknown network-related error was detected");
case QNetworkReply::UnknownProxyError:
return tr("An unknown proxy-related error was detected");
case QNetworkReply::UnknownContentError:
return tr("An unknown error related to the remote content was detected");
case QNetworkReply::ProtocolFailure:
return tr("A breakdown in protocol was detected");
default:
return tr("Unknown error");
}
}
#ifndef QT_NO_OPENSSL
void DownloadThread::ignoreSslErrors(QNetworkReply* reply, const QList<QSslError> &errors) {
Q_UNUSED(errors)
// Ignore all SSL errors
reply->ignoreSslErrors();
}
#endif

View File

@@ -0,0 +1,278 @@
#include <QtGlobal>
#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 "core/preferences.h"
#include "core/bittorrent/torrentinfo.h"
#include "core/bittorrent/magneturi.h"
#include "filesystemwatcher.h"
#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)
{
m_filters << "*.torrent" << "*.magnet";
connect(this, SIGNAL(directoryChanged(QString)), SLOT(scanLocalFolder(QString)));
}
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;
#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 !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 (isNetworkFileSystem(path)) {
// Network mode
qDebug("Network folder detected: %s", qPrintable(path));
qDebug("Using file polling mode instead of inotify...");
m_watchedFolders << dir;
// 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", qPrintable(path));
QFileSystemWatcher::addPath(path);
scanLocalFolder(path);
#if !defined Q_OS_WIN && !defined Q_OS_HAIKU
}
#endif
}
void FileSystemWatcher::removePath(const QString &path)
{
#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(QString path)
{
qDebug("scanLocalFolder(%s) called", qPrintable(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", qPrintable(torrents.join("\n")));
emit torrentsAdded(torrents);
}
}
void FileSystemWatcher::scanNetworkFolders()
{
#ifndef Q_OS_WIN
qDebug("scanNetworkFolders() called");
QStringList torrents;
// Network folders scan
foreach (const QDir &dir, m_watchedFolders) {
//qDebug("FSWatcher: Polling manually folder %s", qPrintable(dir.path()));
addTorrentsFromDir(dir, torrents);
}
// Report detected torrent files
if (!torrents.empty()) {
qDebug("The following files are being reported: %s", qPrintable(torrents.join("\n")));
emit torrentsAdded(torrents);
}
#endif
}
void FileSystemWatcher::processPartialTorrents()
{
QStringList noLongerPartial;
// Check which torrents are still partial
foreach (const QString &torrentPath, m_partialTorrents.keys()) {
if (!QFile::exists(torrentPath)) {
m_partialTorrents.remove(torrentPath);
}
else if (BitTorrent::TorrentInfo::loadFromFile(torrentPath).isValid()) {
noLongerPartial << torrentPath;
m_partialTorrents.remove(torrentPath);
}
else if (m_partialTorrents[torrentPath] >= MAX_PARTIAL_RETRIES) {
m_partialTorrents.remove(torrentPath);
QFile::rename(torrentPath, torrentPath + ".invalid");
}
else {
++m_partialTorrents[torrentPath];
}
}
// Stop the partial timer if necessary
if (m_partialTorrents.empty()) {
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);
}
// Notify of new torrents
if (!noLongerPartial.isEmpty())
emit torrentsAdded(noLongerPartial);
}
void FileSystemWatcher::startPartialTorrentTimer()
{
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 (fileAbsPath.endsWith(".magnet")) {
QFile f(fileAbsPath);
if (f.open(QIODevice::ReadOnly)
&& !BitTorrent::MagnetUri(QString::fromLocal8Bit(f.readAll())).isValid()) {
torrents << fileAbsPath;
}
}
else if (BitTorrent::TorrentInfo::loadFromFile(fileAbsPath).isValid()) {
torrents << fileAbsPath;
}
else if (!m_partialTorrents.contains(fileAbsPath)) {
qDebug("Partial torrent detected at: %s", qPrintable(fileAbsPath));
qDebug("Delay the file's processing...");
m_partialTorrents.insert(fileAbsPath, 0);
}
}
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 == (long)CIFS_MAGIC_NUMBER) || (buf.f_type == (long)NFS_SUPER_MAGIC) || (buf.f_type == (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

@@ -8,290 +8,45 @@
#include <QStringList>
#include <QHash>
#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 "fs_utils.h"
#include "misc.h"
#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;
/*
* Subclassing QFileSystemWatcher in order to support Network File
* System watching (NFS, CIFS) on Linux and Mac OS.
*/
class FileSystemWatcher: public QFileSystemWatcher {
Q_OBJECT
private:
#ifndef Q_OS_WIN
QList<QDir> watched_folders;
QPointer<QTimer> watch_timer;
#endif
QStringList m_filters;
// Partial torrents
QHash<QString, int> m_partialTorrents;
QPointer<QTimer> m_partialTorrentTimer;
#if !defined Q_OS_WIN && !defined Q_OS_HAIKU
private:
static bool 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 == (long)CIFS_MAGIC_NUMBER || buf.f_type == (long)NFS_SUPER_MAGIC || buf.f_type == (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
class FileSystemWatcher : public QFileSystemWatcher
{
Q_OBJECT
public:
FileSystemWatcher(QObject *parent): QFileSystemWatcher(parent) {
m_filters << "*.torrent" << "*.magnet";
connect(this, SIGNAL(directoryChanged(QString)), this, SLOT(scanLocalFolder(QString)));
}
explicit FileSystemWatcher(QObject *parent = 0);
~FileSystemWatcher();
~FileSystemWatcher() {
#ifndef Q_OS_WIN
if (watch_timer)
delete watch_timer;
#endif
if (m_partialTorrentTimer)
delete m_partialTorrentTimer;
}
QStringList directories() const {
QStringList dirs;
#ifndef Q_OS_WIN
if (watch_timer) {
foreach (const QDir &dir, watched_folders)
dirs << dir.canonicalPath();
}
#endif
dirs << QFileSystemWatcher::directories();
return dirs;
}
void addPath(const QString & 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 (isNetworkFileSystem(path)) {
// Network mode
qDebug("Network folder detected: %s", qPrintable(path));
qDebug("Using file polling mode instead of inotify...");
watched_folders << dir;
// Set up the watch timer
if (!watch_timer) {
watch_timer = new QTimer(this);
connect(watch_timer, SIGNAL(timeout()), this, SLOT(scanNetworkFolders()));
watch_timer->start(WATCH_INTERVAL); // 5 sec
}
} else {
#endif
// Normal mode
qDebug("FS Watching is watching %s in normal mode", qPrintable(path));
QFileSystemWatcher::addPath(path);
scanLocalFolder(path);
#if !defined Q_OS_WIN && !defined Q_OS_HAIKU
}
#endif
}
void removePath(const QString & path) {
#ifndef Q_OS_WIN
QDir dir(path);
for (int i = 0; i < watched_folders.count(); ++i) {
if (QDir(watched_folders.at(i)) == dir) {
watched_folders.removeAt(i);
if (watched_folders.isEmpty())
delete watch_timer;
return;
}
}
#endif
// Normal mode
QFileSystemWatcher::removePath(path);
}
protected slots:
void scanLocalFolder(QString path) {
qDebug("scanLocalFolder(%s) called", qPrintable(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", qPrintable(torrents.join("\n")));
emit torrentsAdded(torrents);
}
}
void scanNetworkFolders() {
#ifndef Q_OS_WIN
qDebug("scanNetworkFolders() called");
QStringList torrents;
// Network folders scan
foreach (const QDir &dir, watched_folders) {
//qDebug("FSWatcher: Polling manually folder %s", qPrintable(dir.path()));
addTorrentsFromDir(dir, torrents);
}
// Report detected torrent files
if (!torrents.empty()) {
qDebug("The following files are being reported: %s", qPrintable(torrents.join("\n")));
emit torrentsAdded(torrents);
}
#endif
}
void processPartialTorrents() {
QStringList no_longer_partial;
// Check which torrents are still partial
foreach (const QString& torrent_path, m_partialTorrents.keys()) {
if (!QFile::exists(torrent_path)) {
m_partialTorrents.remove(torrent_path);
continue;
}
if (fsutils::isValidTorrentFile(torrent_path)) {
no_longer_partial << torrent_path;
m_partialTorrents.remove(torrent_path);
} else {
if (m_partialTorrents[torrent_path] >= MAX_PARTIAL_RETRIES) {
m_partialTorrents.remove(torrent_path);
QFile::rename(torrent_path, torrent_path+".invalid");
} else {
m_partialTorrents[torrent_path]++;
}
}
}
// Stop the partial timer if necessary
if (m_partialTorrents.empty()) {
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);
}
// Notify of new torrents
if (!no_longer_partial.isEmpty())
emit torrentsAdded(no_longer_partial);
}
QStringList directories() const;
void addPath(const QString &path);
void removePath(const QString &path);
signals:
void torrentsAdded(QStringList &pathList);
void torrentsAdded(const QStringList &pathList);
protected slots:
void scanLocalFolder(QString path);
void scanNetworkFolders();
void processPartialTorrents();
private:
void startPartialTorrentTimer() {
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 addTorrentsFromDir(const QDir &dir, QStringList &torrents) {
const QStringList files = dir.entryList(m_filters, QDir::Files, QDir::Unsorted);
foreach (const QString &file, files) {
const QString file_abspath = dir.absoluteFilePath(file);
if (file_abspath.endsWith(".magnet")) {
QFile f(file_abspath);
if (f.open(QIODevice::ReadOnly)
&& !misc::magnetUriToHash(QString::fromLocal8Bit(f.readAll())).isEmpty()) {
torrents << file_abspath;
}
} else if (fsutils::isValidTorrentFile(file_abspath)) {
torrents << file_abspath;
} else {
if (!m_partialTorrents.contains(file_abspath)) {
qDebug("Partial torrent detected at: %s", qPrintable(file_abspath));
qDebug("Delay the file's processing...");
m_partialTorrents.insert(file_abspath, 0);
}
}
}
if (!m_partialTorrents.empty())
startPartialTorrentTimer();
}
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;
QPointer<QTimer> m_partialTorrentTimer;
};
#endif // FILESYSTEMWATCHER_H

View File

@@ -1,552 +0,0 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2012 Christophe Dumez
*
* 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.
*
* Contact : chris@qbittorrent.org
*/
#include "fs_utils.h"
#include "misc.h"
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QSettings>
#ifdef DISABLE_GUI
#include <QCoreApplication>
#else
#include <QApplication>
#endif
#include <libtorrent/torrent_info.hpp>
#ifdef Q_OS_MAC
#include <CoreServices/CoreServices.h>
#include <Carbon/Carbon.h>
#endif
#ifndef Q_OS_WIN
#if defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)
#include <sys/param.h>
#include <sys/mount.h>
#elif defined(Q_OS_HAIKU)
#include <kernel/fs_info.h>
#else
#include <sys/vfs.h>
#endif
#else
#include <shlobj.h>
#include <winbase.h>
#endif
#if defined(Q_OS_WIN) || defined(Q_OS_OS2)
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
#include <QDesktopServices>
#else
#include <QStandardPaths>
#endif
#endif
using namespace libtorrent;
/**
* Converts a path to a string suitable for display.
* This function makes sure the directory separator used is consistent
* with the OS being run.
*/
QString fsutils::toNativePath(const QString& path) {
return QDir::toNativeSeparators(path);
}
QString fsutils::fromNativePath(const QString &path) {
return QDir::fromNativeSeparators(path);
}
/**
* Returns the file extension part of a file name.
*/
QString fsutils::fileExtension(const QString &filename) {
QString ext = QString(filename).remove(".!qB");
const int point_index = ext.lastIndexOf(".");
return (point_index >= 0) ? ext.mid(point_index + 1) : QString();
}
QString fsutils::fileName(const QString& file_path) {
QString path = fsutils::fromNativePath(file_path);
const int slash_index = path.lastIndexOf("/");
if (slash_index == -1)
return path;
return path.mid(slash_index + 1);
}
QString fsutils::folderName(const QString& file_path) {
QString path = fsutils::fromNativePath(file_path);
const int slash_index = path.lastIndexOf("/");
if (slash_index == -1)
return path;
return path.left(slash_index);
}
bool fsutils::isValidTorrentFile(const QString& torrent_path) {
try {
boost::intrusive_ptr<libtorrent::torrent_info> t = new torrent_info(fsutils::toNativePath(torrent_path).toUtf8().constData());
if (!t->is_valid() || t->num_files() == 0)
return false;
} catch(std::exception&) {
return false;
}
return true;
}
/**
* Remove an empty folder tree.
*
* This function will also remove .DS_Store files on Mac OS and
* Thumbs.db on Windows.
*/
bool fsutils::smartRemoveEmptyFolderTree(const QString& dir_path) {
qDebug() << Q_FUNC_INFO << dir_path;
if (dir_path.isEmpty())
return false;
QDir dir(dir_path);
if (!dir.exists())
return true;
// Remove Files created by the OS
#if defined Q_OS_MAC
fsutils::forceRemove(dir_path + QLatin1String("/.DS_Store"));
#elif defined Q_OS_WIN
fsutils::forceRemove(dir_path + QLatin1String("/Thumbs.db"));
#endif
QFileInfoList sub_files = dir.entryInfoList();
foreach (const QFileInfo& info, sub_files) {
QString sub_name = info.fileName();
if (sub_name == "." || sub_name == "..")
continue;
QString sub_path = info.absoluteFilePath();
qDebug() << Q_FUNC_INFO << "sub file: " << sub_path;
if (info.isDir()) {
if (!smartRemoveEmptyFolderTree(sub_path)) {
qWarning() << Q_FUNC_INFO << "Failed to remove folder: " << sub_path;
return false;
}
} else {
if (info.isHidden()) {
qDebug() << Q_FUNC_INFO << "Removing hidden file: " << sub_path;
if (!fsutils::forceRemove(sub_path)) {
qWarning() << Q_FUNC_INFO << "Failed to remove " << sub_path;
return false;
}
} else {
qWarning() << Q_FUNC_INFO << "Folder is not empty, aborting. Found: " << sub_path;
}
}
}
qDebug() << Q_FUNC_INFO << "Calling rmdir on " << dir_path;
return QDir().rmdir(dir_path);
}
/**
* Removes the file with the given file_path.
*
* This function will try to fix the file permissions before removing it.
*/
bool fsutils::forceRemove(const QString& file_path) {
QFile f(file_path);
if (!f.exists())
return true;
// Make sure we have read/write permissions
f.setPermissions(f.permissions()|QFile::ReadOwner|QFile::WriteOwner|QFile::ReadUser|QFile::WriteUser);
// Remove the file
return f.remove();
}
/**
* Removes directory and its content recursively.
*
*/
void fsutils::removeDirRecursive(const QString& dirName) {
QDir dir(dirName);
if (!dir.exists()) return;
Q_FOREACH(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot |
QDir::System |
QDir::Hidden |
QDir::AllDirs |
QDir::Files, QDir::DirsFirst)) {
if (info.isDir()) removeDirRecursive(info.absoluteFilePath());
else forceRemove(info.absoluteFilePath());
}
dir.rmdir(dirName);
}
/**
* Returns the size of a file.
* If the file is a folder, it will compute its size based on its content.
*
* Returns -1 in case of error.
*/
qint64 fsutils::computePathSize(const QString& path) {
// Check if it is a file
QFileInfo fi(path);
if (!fi.exists()) return -1;
if (fi.isFile()) return fi.size();
// Compute folder size based on its content
qint64 size = 0;
foreach (const QFileInfo &subfi, QDir(path).entryInfoList(QDir::Dirs|QDir::Files)) {
if (subfi.fileName().startsWith(".")) continue;
if (subfi.isDir())
size += fsutils::computePathSize(subfi.absoluteFilePath());
else
size += subfi.size();
}
return size;
}
/**
* Makes deep comparison of two files to make sure they are identical.
*/
bool fsutils::sameFiles(const QString& path1, const QString& path2) {
QFile f1(path1), f2(path2);
if (!f1.exists() || !f2.exists()) return false;
if (f1.size() != f2.size()) return false;
if (!f1.open(QIODevice::ReadOnly)) return false;
if (!f2.open(QIODevice::ReadOnly)) {
f1.close();
return false;
}
bool same = true;
while(!f1.atEnd() && !f2.atEnd()) {
if (f1.read(1024) != f2.read(1024)) {
same = false;
break;
}
}
f1.close(); f2.close();
return same;
}
QString fsutils::updateLabelInSavePath(const QString& defaultSavePath, const QString& save_path, const QString& old_label, const QString& new_label) {
if (old_label == new_label) return fsutils::fromNativePath(save_path);
QString defaultPath = fsutils::fromNativePath(defaultSavePath);
QString path = fsutils::fromNativePath(save_path);
qDebug("UpdateLabelInSavePath(%s, %s, %s)", qPrintable(path), qPrintable(old_label), qPrintable(new_label));
if (!path.startsWith(defaultPath)) return path;
QString new_save_path = path;
new_save_path.remove(defaultPath);
QStringList path_parts = new_save_path.split("/", QString::SkipEmptyParts);
if (path_parts.empty()) {
if (!new_label.isEmpty())
path_parts << new_label;
} else {
if (old_label.isEmpty() || path_parts.first() != old_label) {
if (path_parts.first() != new_label)
path_parts.prepend(new_label);
} else {
if (new_label.isEmpty()) {
path_parts.removeAt(0);
} else {
if (path_parts.first() != new_label)
path_parts.replace(0, new_label);
}
}
}
new_save_path = defaultPath;
if (!new_save_path.endsWith("/")) new_save_path += "/";
new_save_path += path_parts.join("/");
qDebug("New save path is %s", qPrintable(new_save_path));
return new_save_path;
}
QString fsutils::toValidFileSystemName(QString filename) {
qDebug("toValidFSName: %s", qPrintable(filename));
const QRegExp regex("[\\\\/:?\"*<>|]");
filename.replace(regex, " ");
qDebug("toValidFSName, result: %s", qPrintable(filename));
return filename.trimmed();
}
bool fsutils::isValidFileSystemName(const QString& filename) {
if (filename.isEmpty()) return false;
const QRegExp regex("[\\\\/:?\"*<>|]");
return !filename.contains(regex);
}
long long fsutils::freeDiskSpaceOnPath(QString path) {
if (path.isEmpty()) return -1;
QDir dir_path(path);
if (!dir_path.exists()) {
QStringList parts = path.split("/");
while (parts.size() > 1 && !QDir(parts.join("/")).exists()) {
parts.removeLast();
}
dir_path = QDir(parts.join("/"));
if (!dir_path.exists()) return -1;
}
Q_ASSERT(dir_path.exists());
#ifndef Q_OS_WIN
unsigned long long available;
#ifdef Q_OS_HAIKU
const QString statfs_path = dir_path.path()+"/.";
dev_t device = dev_for_path (qPrintable(statfs_path));
if (device >= 0) {
fs_info info;
if(fs_stat_dev(device, &info)==B_OK){
available = ((unsigned long long)(info.free_blocks*info.block_size));
return available;
}
}
return -1;
#else
struct statfs stats;
const QString statfs_path = dir_path.path()+"/.";
const int ret = statfs (qPrintable(statfs_path), &stats) ;
if (ret == 0) {
available = ((unsigned long long)stats.f_bavail) *
((unsigned long long)stats.f_bsize) ;
return available;
} else {
return -1;
}
#endif
#else
typedef BOOL (WINAPI *GetDiskFreeSpaceEx_t)(LPCTSTR,
PULARGE_INTEGER,
PULARGE_INTEGER,
PULARGE_INTEGER);
GetDiskFreeSpaceEx_t
pGetDiskFreeSpaceEx = (GetDiskFreeSpaceEx_t)::GetProcAddress
(
::GetModuleHandle(TEXT("kernel32.dll")),
"GetDiskFreeSpaceExW"
);
if ( pGetDiskFreeSpaceEx )
{
ULARGE_INTEGER bytesFree, bytesTotal;
unsigned long long *ret;
if (pGetDiskFreeSpaceEx((LPCTSTR)(fsutils::toNativePath(dir_path.path())).utf16(), &bytesFree, &bytesTotal, NULL)) {
ret = (unsigned long long*)&bytesFree;
return *ret;
} else {
return -1;
}
} else {
return -1;
}
#endif
}
QString fsutils::branchPath(const QString& file_path, QString* removed) {
QString ret = fsutils::fromNativePath(file_path);
if (ret.endsWith("/"))
ret.chop(1);
const int slashIndex = ret.lastIndexOf("/");
if (slashIndex >= 0) {
if (removed)
*removed = ret.mid(slashIndex + 1);
ret = ret.left(slashIndex);
}
return ret;
}
bool fsutils::sameFileNames(const QString &first, const QString &second) {
#if defined(Q_OS_UNIX) || defined(Q_WS_QWS)
return QString::compare(first, second, Qt::CaseSensitive) == 0;
#else
return QString::compare(first, second, Qt::CaseInsensitive) == 0;
#endif
}
QString fsutils::expandPath(const QString &path) {
QString ret = fsutils::fromNativePath(path.trimmed());
if (ret.isEmpty())
return ret;
return QDir::cleanPath(ret);
}
QString fsutils::expandPathAbs(const QString& path) {
QString ret = fsutils::expandPath(path);
if (!QDir::isAbsolutePath(ret))
ret = QDir(ret).absolutePath();
return ret;
}
QString fsutils::QDesktopServicesDataLocation() {
QString result;
#ifdef Q_OS_WIN
LPWSTR path=new WCHAR[256];
if (SHGetSpecialFolderPath(0, path, CSIDL_LOCAL_APPDATA, FALSE))
result = fsutils::fromNativePath(QString::fromWCharArray(path));
if (!QCoreApplication::applicationName().isEmpty())
result += QLatin1String("/") + qApp->applicationName();
#else
#ifdef Q_OS_MAC
FSRef ref;
OSErr err = FSFindFolder(kUserDomain, kApplicationSupportFolderType, false, &ref);
if (err)
return QString();
QString path;
QByteArray ba(2048, 0);
if (FSRefMakePath(&ref, reinterpret_cast<UInt8 *>(ba.data()), ba.size()) == noErr)
result = QString::fromUtf8(ba).normalized(QString::NormalizationForm_C);
result += QLatin1Char('/') + qApp->applicationName();
#else
QString xdgDataHome = QLatin1String(qgetenv("XDG_DATA_HOME"));
if (xdgDataHome.isEmpty())
xdgDataHome = QDir::homePath() + QLatin1String("/.local/share");
xdgDataHome += QLatin1String("/data/")
+ qApp->applicationName();
result = xdgDataHome;
#endif
#endif
if (!result.endsWith("/"))
result += "/";
return result;
}
QString fsutils::QDesktopServicesCacheLocation() {
QString result;
#if defined(Q_OS_WIN) || defined(Q_OS_OS2)
result = QDesktopServicesDataLocation() + QLatin1String("cache");
#else
#ifdef Q_OS_MAC
// http://developer.apple.com/documentation/Carbon/Reference/Folder_Manager/Reference/reference.html
FSRef ref;
OSErr err = FSFindFolder(kUserDomain, kCachedDataFolderType, false, &ref);
if (err)
return QString();
QByteArray ba(2048, 0);
if (FSRefMakePath(&ref, reinterpret_cast<UInt8 *>(ba.data()), ba.size()) == noErr)
result = QString::fromUtf8(ba).normalized(QString::NormalizationForm_C);
result += QLatin1Char('/') + qApp->applicationName();
#else
QString xdgCacheHome = QLatin1String(qgetenv("XDG_CACHE_HOME"));
if (xdgCacheHome.isEmpty())
xdgCacheHome = QDir::homePath() + QLatin1String("/.cache");
xdgCacheHome += QLatin1Char('/') + QCoreApplication::applicationName();
result = xdgCacheHome;
#endif
#endif
if (!result.endsWith("/"))
result += "/";
return result;
}
QString fsutils::QDesktopServicesDownloadLocation() {
#if defined(Q_OS_WIN) || defined(Q_OS_OS2)
// as long as it stays WinXP like we do the same on OS/2
// TODO: Use IKnownFolderManager to get path of FOLDERID_Downloads
// instead of hardcoding "Downloads"
// Unfortunately, this would break compatibility with WinXP
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
return QDir(QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation)).absoluteFilePath(
QCoreApplication::translate("fsutils", "Downloads"));
#else
return QDir(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)).absoluteFilePath(
QCoreApplication::translate("fsutils", "Downloads"));
#endif
#endif
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
QString save_path;
// Default save path on Linux
QString config_path = QString::fromLocal8Bit(qgetenv("XDG_CONFIG_HOME").constData());
if (config_path.isEmpty())
config_path = QDir::home().absoluteFilePath(".config");
QString user_dirs_file = config_path + "/user-dirs.dirs";
if (QFile::exists(user_dirs_file)) {
QSettings settings(user_dirs_file, QSettings::IniFormat);
// We need to force UTF-8 encoding here since this is not
// the default for Ini files.
settings.setIniCodec("UTF-8");
QString xdg_download_dir = settings.value("XDG_DOWNLOAD_DIR").toString();
if (!xdg_download_dir.isEmpty()) {
// Resolve $HOME environment variables
xdg_download_dir.replace("$HOME", QDir::homePath());
save_path = xdg_download_dir;
qDebug() << Q_FUNC_INFO << "SUCCESS: Using XDG path for downloads: " << save_path;
}
}
// Fallback
if (!save_path.isEmpty() && !QFile::exists(save_path)) {
QDir().mkpath(save_path);
}
if (save_path.isEmpty() || !QFile::exists(save_path)) {
save_path = QDir::home().absoluteFilePath(QCoreApplication::translate("fsutils", "Downloads"));
qDebug() << Q_FUNC_INFO << "using" << save_path << "as fallback since the XDG detection did not work";
}
return save_path;
#endif
#ifdef Q_OS_MAC
// TODO: How to support this on Mac OS X?
#endif
// Fallback
return QDir::home().absoluteFilePath(QCoreApplication::translate("fsutils", "Downloads"));
}
QString fsutils::searchEngineLocation() {
QString folder = "nova";
if (misc::pythonVersion() >= 3)
folder = "nova3";
const QString location = fsutils::expandPathAbs(QDesktopServicesDataLocation()
+ folder);
QDir locationDir(location);
if (!locationDir.exists())
locationDir.mkpath(locationDir.absolutePath());
return location;
}
QString fsutils::BTBackupLocation() {
const QString location = fsutils::expandPathAbs(QDesktopServicesDataLocation()
+ "BT_backup");
QDir locationDir(location);
if (!locationDir.exists())
locationDir.mkpath(locationDir.absolutePath());
return location;
}
QString fsutils::cacheLocation() {
QString location = fsutils::expandPathAbs(QDesktopServicesCacheLocation());
QDir locationDir(location);
if (!locationDir.exists())
locationDir.mkpath(locationDir.absolutePath());
return location;
}

View File

@@ -1,74 +0,0 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2012 Christophe Dumez
*
* 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.
*
* Contact : chris@qbittorrent.org
*/
#ifndef FS_UTILS_H
#define FS_UTILS_H
#include <QString>
/**
* Utility functions related to file system.
*/
namespace fsutils
{
QString toNativePath(const QString& path);
QString fromNativePath(const QString& path);
QString fileExtension(const QString& filename);
QString fileName(const QString& file_path);
QString folderName(const QString& file_path);
qint64 computePathSize(const QString& path);
bool sameFiles(const QString& path1, const QString& path2);
QString updateLabelInSavePath(const QString &defaultSavePath, const QString &save_path, const QString& old_label, const QString& new_label);
QString toValidFileSystemName(QString filename);
bool isValidFileSystemName(const QString& filename);
long long freeDiskSpaceOnPath(QString path);
QString branchPath(const QString& file_path, QString* removed = 0);
bool sameFileNames(const QString& first, const QString& second);
QString expandPath(const QString& path);
QString expandPathAbs(const QString& path);
bool isValidTorrentFile(const QString& path);
bool smartRemoveEmptyFolderTree(const QString& dir_path);
bool forceRemove(const QString& file_path);
void removeDirRecursive(const QString& dirName);
/* Ported from Qt4 to drop dependency on QtGui */
QString QDesktopServicesDataLocation();
QString QDesktopServicesCacheLocation();
QString QDesktopServicesDownloadLocation();
/* End of Qt4 code */
QString searchEngineLocation();
QString BTBackupLocation();
QString cacheLocation();
}
#endif // FS_UTILS_H

View File

@@ -42,30 +42,28 @@ QT_END_NAMESPACE
namespace Http
{
class IRequestHandler;
class IRequestHandler;
class Connection : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Connection)
class Connection : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Connection)
public:
Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = 0);
~Connection();
public:
Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = 0);
~Connection();
private slots:
void read();
private slots:
void read();
private:
static bool acceptsGzipEncoding(const QString &encoding);
void sendResponse(const Response &response);
QTcpSocket *m_socket;
IRequestHandler *m_requestHandler;
QByteArray m_receivedData;
};
private:
static bool acceptsGzipEncoding(const QString &encoding);
void sendResponse(const Response &response);
QTcpSocket *m_socket;
IRequestHandler *m_requestHandler;
QByteArray m_receivedData;
};
}
#endif // HTTP_CONNECTION_H

View File

@@ -33,14 +33,12 @@
namespace Http
{
class IRequestHandler
{
public:
virtual ~IRequestHandler() {}
virtual Response processRequest(const Request &request, const Environment &env) = 0;
};
class IRequestHandler
{
public:
virtual ~IRequestHandler() {}
virtual Response processRequest(const Request &request, const Environment &env) = 0;
};
}
#endif // HTTP_IREQUESTHANDLER_H

View File

@@ -36,39 +36,37 @@
namespace Http
{
class RequestParser
{
public:
enum ErrorCode
class RequestParser
{
NoError = 0,
IncompleteRequest,
BadRequest
public:
enum ErrorCode
{
NoError = 0,
IncompleteRequest,
BadRequest
};
// 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(uint maxContentLength);
ErrorCode parseHttpRequest(const QByteArray &data, Request &request);
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;
};
// 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(uint maxContentLength);
ErrorCode parseHttpRequest(const QByteArray &data, Request &request);
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;
};
}
#endif // HTTP_REQUESTPARSER_H

View File

@@ -34,27 +34,25 @@
namespace Http
{
class ResponseBuilder : public QObject
{
public:
explicit ResponseBuilder(QObject *parent = 0);
class ResponseBuilder : public QObject
{
public:
explicit ResponseBuilder(QObject *parent = 0);
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);
void print(const QByteArray &data, const QString &type = CONTENT_TYPE_HTML);
void clear();
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);
void print(const QByteArray &data, const QString &type = CONTENT_TYPE_HTML);
void clear();
Response response() const;
Response response() const;
private:
void print_impl(const QByteArray &data, const QString &type);
Response m_response;
};
private:
void print_impl(const QByteArray &data, const QString &type);
Response m_response;
};
}
#endif // HTTP_RESPONSEBUILDER_H

View File

@@ -29,11 +29,9 @@
* Contact : chris@qbittorrent.org
*/
#include <zlib.h>
#include "core/utils/gzip.h"
#include "responsegenerator.h"
bool gCompress(QByteArray data, QByteArray& dest_buffer);
using namespace Http;
QByteArray ResponseGenerator::generate(Response response)
@@ -44,7 +42,7 @@ QByteArray ResponseGenerator::generate(Response response)
// So we only benefit from gzip if the message is bigger than 23+26 = 49
// If the message is smaller than 49 bytes we actually send MORE data if we gzip
QByteArray dest_buf;
if ((response.content.size() > 49) && (gCompress(response.content, dest_buf)))
if ((response.content.size() > 49) && (Utils::Gzip::compress(response.content, dest_buf)))
response.content = dest_buf;
else
response.headers.remove(HEADER_CONTENT_ENCODING);
@@ -67,58 +65,3 @@ QByteArray ResponseGenerator::generate(Response response)
return ret.toUtf8() + response.content;
}
bool gCompress(QByteArray data, QByteArray& dest_buffer)
{
static const int BUFSIZE = 128 * 1024;
char tmp_buf[BUFSIZE];
int ret;
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.next_in = reinterpret_cast<unsigned char*>(data.data());
strm.avail_in = data.length();
strm.next_out = reinterpret_cast<unsigned char*>(tmp_buf);
strm.avail_out = BUFSIZE;
//windowBits = 15+16 to enable gzip
//From the zlib manual: windowBits can also be greater than 15 for optional gzip encoding. Add 16 to windowBits
//to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper.
ret = deflateInit2(&strm, Z_BEST_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY);
if (ret != Z_OK)
return false;
while (strm.avail_in != 0) {
ret = deflate(&strm, Z_NO_FLUSH);
if (ret != Z_OK)
return false;
if (strm.avail_out == 0) {
dest_buffer.append(tmp_buf, BUFSIZE);
strm.next_out = reinterpret_cast<unsigned char*>(tmp_buf);
strm.avail_out = BUFSIZE;
}
}
int deflate_res = Z_OK;
while (deflate_res == Z_OK) {
if (strm.avail_out == 0) {
dest_buffer.append(tmp_buf, BUFSIZE);
strm.next_out = reinterpret_cast<unsigned char*>(tmp_buf);
strm.avail_out = BUFSIZE;
}
deflate_res = deflate(&strm, Z_FINISH);
}
if (deflate_res != Z_STREAM_END)
return false;
dest_buffer.append(tmp_buf, BUFSIZE - strm.avail_out);
deflateEnd(&strm);
return true;
}

View File

@@ -37,13 +37,11 @@
namespace Http
{
class ResponseGenerator
{
public:
static QByteArray generate(Response response);
};
class ResponseGenerator
{
public:
static QByteArray generate(Response response);
};
}
#endif // HTTP_RESPONSEGENERATOR_H

View File

@@ -38,7 +38,7 @@
using namespace Http;
Server::Server(IRequestHandler *requestHandler, QObject* parent)
Server::Server(IRequestHandler *requestHandler, QObject *parent)
: QTcpServer(parent)
, m_requestHandler(requestHandler)
#ifndef QT_NO_OPENSSL

View File

@@ -41,40 +41,38 @@
namespace Http
{
class IRequestHandler;
class Connection;
class IRequestHandler;
class Connection;
class Server : public QTcpServer
{
Q_OBJECT
Q_DISABLE_COPY(Server)
class Server : public QTcpServer
{
Q_OBJECT
Q_DISABLE_COPY(Server)
public:
Server(IRequestHandler *requestHandler, QObject *parent = 0);
~Server();
public:
Server(IRequestHandler *requestHandler, QObject *parent = 0);
~Server();
#ifndef QT_NO_OPENSSL
void enableHttps(const QSslCertificate &certificate, const QSslKey &key);
void disableHttps();
#endif
#ifndef QT_NO_OPENSSL
void enableHttps(const QSslCertificate &certificate, const QSslKey &key);
void disableHttps();
#endif
private:
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
void incomingConnection(qintptr socketDescriptor);
#else
void incomingConnection(int socketDescriptor);
#endif
private:
IRequestHandler *m_requestHandler;
#ifndef QT_NO_OPENSSL
bool m_https;
QSslCertificate m_certificate;
QSslKey m_key;
#endif
};
private:
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
void incomingConnection(qintptr socketDescriptor);
#else
void incomingConnection(int socketDescriptor);
#endif
private:
IRequestHandler *m_requestHandler;
#ifndef QT_NO_OPENSSL
bool m_https;
QSslCertificate m_certificate;
QSslKey m_key;
#endif
};
}
#endif // HTTP_SERVER_H

View File

@@ -37,60 +37,58 @@ typedef QMap<QString, QString> QStringMap;
namespace Http
{
const QString HEADER_SET_COOKIE = "Set-Cookie";
const QString HEADER_CONTENT_TYPE = "Content-Type";
const QString HEADER_CONTENT_ENCODING = "Content-Encoding";
const QString HEADER_CONTENT_LENGTH = "Content-Length";
const QString HEADER_CACHE_CONTROL = "Cache-Control";
const QString HEADER_SET_COOKIE = "Set-Cookie";
const QString HEADER_CONTENT_TYPE = "Content-Type";
const QString HEADER_CONTENT_ENCODING = "Content-Encoding";
const QString HEADER_CONTENT_LENGTH = "Content-Length";
const QString HEADER_CACHE_CONTROL = "Cache-Control";
const QString CONTENT_TYPE_CSS = "text/css; charset=UTF-8";
const QString CONTENT_TYPE_GIF = "image/gif";
const QString CONTENT_TYPE_HTML = "text/html; charset=UTF-8";
const QString CONTENT_TYPE_JS = "application/javascript; charset=UTF-8";
const QString CONTENT_TYPE_JSON = "application/json";
const QString CONTENT_TYPE_PNG = "image/png";
const QString CONTENT_TYPE_TXT = "text/plain; charset=UTF-8";
const QString CONTENT_TYPE_CSS = "text/css; charset=UTF-8";
const QString CONTENT_TYPE_GIF = "image/gif";
const QString CONTENT_TYPE_HTML = "text/html; charset=UTF-8";
const QString CONTENT_TYPE_JS = "application/javascript; charset=UTF-8";
const QString CONTENT_TYPE_JSON = "application/json";
const QString CONTENT_TYPE_PNG = "image/png";
const QString CONTENT_TYPE_TXT = "text/plain; charset=UTF-8";
struct Environment
{
QHostAddress clientAddress;
};
struct Environment
{
QHostAddress clientAddress;
};
struct UploadedFile
{
QString filename; // original filename
QString type; // MIME type
QByteArray data; // File data
};
struct UploadedFile
{
QString filename; // original filename
QString type; // MIME type
QByteArray data; // File data
};
struct Request
{
QString method;
QString path;
QStringMap headers;
QStringMap gets;
QStringMap posts;
QMap<QString, UploadedFile> files;
};
struct Request
{
QString method;
QString path;
QStringMap headers;
QStringMap gets;
QStringMap posts;
QMap<QString, UploadedFile> files;
};
struct ResponseStatus
{
uint code;
QString text;
struct ResponseStatus
{
uint code;
QString text;
ResponseStatus(uint code = 200, const QString& text = "OK"): code(code), text(text) {}
};
ResponseStatus(uint code = 200, const QString& text = "OK"): code(code), text(text) {}
};
struct Response
{
ResponseStatus status;
QStringMap headers;
QByteArray content;
Response(uint code = 200, const QString& text = "OK"): status(code, text) {}
};
struct Response
{
ResponseStatus status;
QStringMap headers;
QByteArray content;
Response(uint code = 200, const QString& text = "OK"): status(code, text) {}
};
}
#endif // HTTP_TYPES_H

64
src/core/iconprovider.cpp Normal file
View File

@@ -0,0 +1,64 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2011 Christophe Dumez <chris@qbittorrent.org>
*
* 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 <QString>
#include "iconprovider.h"
IconProvider::IconProvider(QObject *parent)
: QObject(parent)
{
}
IconProvider::~IconProvider() {}
void IconProvider::initInstance()
{
if (!m_instance)
m_instance = new IconProvider;
}
void IconProvider::freeInstance()
{
if (m_instance) {
delete m_instance;
m_instance = 0;
}
}
IconProvider *IconProvider::instance()
{
return m_instance;
}
QString IconProvider::getIconPath(const QString &iconId)
{
return ":/icons/oxygen/" + iconId + ".png";
}
IconProvider *IconProvider::m_instance = 0;

View File

@@ -1,6 +1,7 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2011 Christophe Dumez
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2011 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -24,40 +25,31 @@
* 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 ICONPROVIDER_H
#define ICONPROVIDER_H
#include <QIcon>
#include <QString>
#include <QObject>
class IconProvider
class QString;
class IconProvider : public QObject
{
Q_DISABLE_COPY(IconProvider)
private:
explicit IconProvider();
static IconProvider* m_instance;
Q_DISABLE_COPY(IconProvider)
public:
static IconProvider* instance();
static void drop();
QIcon getIcon(const QString& iconId);
QString getIconPath(const QString& iconId);
static void initInstance();
static void freeInstance();
static IconProvider *instance();
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
public:
void useSystemIconTheme(bool enable);
virtual QString getIconPath(const QString &iconId);
private:
QIcon generateDifferentSizes(const QIcon& icon);
protected:
explicit IconProvider(QObject *parent = 0);
~IconProvider();
private:
bool m_useSystemTheme;
#endif
static IconProvider *m_instance;
};
#endif // ICONPROVIDER_H

View File

@@ -16,18 +16,12 @@ namespace Log
Peer::Peer() {}
#if LIBTORRENT_VERSION_NUM < 10000
Peer::Peer(int id, const QString &ip, bool blocked)
#else
Peer::Peer(int id, const QString &ip, bool blocked, const QString &reason)
#endif
: id(id)
, timestamp(QDateTime::currentMSecsSinceEpoch())
, ip(ip)
, blocked(blocked)
#if LIBTORRENT_VERSION_NUM >= 10000
, reason(reason)
#endif
{
}
@@ -44,15 +38,18 @@ Logger::Logger()
Logger::~Logger() {}
Logger * Logger::instance()
Logger *Logger::instance()
{
if (!m_instance)
m_instance = new Logger;
return m_instance;
}
void Logger::drop()
void Logger::initInstance()
{
if (!m_instance)
m_instance = new Logger;
}
void Logger::freeInstance()
{
if (m_instance) {
delete m_instance;
@@ -73,19 +70,11 @@ void Logger::addMessage(const QString &message, const Log::MsgType &type)
emit newLogMessage(temp);
}
#if LIBTORRENT_VERSION_NUM < 10000
void Logger::addPeer(const QString &ip, bool blocked)
#else
void Logger::addPeer(const QString &ip, bool blocked, const QString &reason)
#endif
{
QWriteLocker locker(&lock);
#if LIBTORRENT_VERSION_NUM < 10000
Log::Peer temp(peerCounter++, ip, blocked);
#else
Log::Peer temp(peerCounter++, ip, blocked, reason);
#endif
m_peers.push_back(temp);
if (m_peers.size() >= MAX_LOG_MESSAGES)

View File

@@ -5,7 +5,6 @@
#include <QVector>
#include <QReadWriteLock>
#include <QObject>
#include <libtorrent/version.hpp>
const int MAX_LOG_MESSAGES = 1000;
@@ -31,19 +30,13 @@ namespace Log
struct Peer
{
#if LIBTORRENT_VERSION_NUM < 10000
Peer(int id, const QString &ip, bool blocked);
#else
Peer(int id, const QString &ip, bool blocked, const QString &reason);
#endif
Peer();
int id;
qint64 timestamp;
QString ip;
bool blocked;
#if LIBTORRENT_VERSION_NUM >= 10000
QString reason;
#endif
};
}
@@ -53,16 +46,12 @@ class Logger : public QObject
Q_DISABLE_COPY(Logger)
public:
static Logger* instance();
static void drop();
~Logger();
static void initInstance();
static void freeInstance();
static Logger *instance();
void addMessage(const QString &message, const Log::MsgType &type = Log::NORMAL);
#if LIBTORRENT_VERSION_NUM < 10000
void addPeer(const QString &ip, bool blocked);
#else
void addPeer(const QString &ip, bool blocked, const QString &reason = QString());
#endif
QVector<Log::Msg> getMessages(int lastKnownId = -1) const;
QVector<Log::Peer> getPeers(int lastKnownId = -1) const;
@@ -72,6 +61,8 @@ signals:
private:
Logger();
~Logger();
static Logger* m_instance;
QVector<Log::Msg> m_messages;
QVector<Log::Peer> m_peers;

View File

@@ -1,120 +0,0 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* 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
* 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.
*
* Contact : chris@qbittorrent.org
*/
#ifndef MISC_H
#define MISC_H
#include <vector>
#include <QString>
#include <QStringList>
#include <ctime>
#include <QPoint>
#include <QFile>
#include <QDir>
#include <QUrl>
#ifndef DISABLE_GUI
#include <QIcon>
#endif
#include <libtorrent/version.hpp>
#include <libtorrent/error_code.hpp>
namespace libtorrent {
#if LIBTORRENT_VERSION_NUM < 10000
class big_number;
typedef big_number sha1_hash;
#else
class sha1_hash;
#endif
struct lazy_entry;
}
const qlonglong MAX_ETA = 8640000;
enum shutDownAction { NO_SHUTDOWN, SHUTDOWN_COMPUTER, SUSPEND_COMPUTER, HIBERNATE_COMPUTER };
/* Miscellaneaous functions that can be useful */
namespace misc
{
QString toQString(const std::string &str);
QString toQString(const char* str);
QString toQString(time_t t, Qt::DateFormat f = Qt::DefaultLocaleLongDate);
QString toQStringU(const std::string &str);
QString toQStringU(const char* str);
QString toQString(const libtorrent::sha1_hash &hash);
#ifndef DISABLE_GUI
void shutdownComputer(shutDownAction action = SHUTDOWN_COMPUTER);
#endif
QString parseHtmlLinks(const QString &raw_text);
bool isUrl(const QString &s);
#ifndef DISABLE_GUI
// Get screen center
QPoint screenCenter(QWidget *win);
#endif
int pythonVersion();
QString pythonExecutable();
QString pythonVersionComplete();
// return best userfriendly storage unit (B, KiB, MiB, GiB, TiB)
// use Binary prefix standards from IEC 60027-2
// see http://en.wikipedia.org/wiki/Kilobyte
// value must be given in bytes
QString friendlyUnit(qreal val, bool is_speed = false);
bool isPreviewable(const QString& extension);
QString magnetUriToName(const QString& magnet_uri);
QString magnetUriToHash(const QString& magnet_uri);
QString bcLinkToMagnet(QString bc_link);
// Take a number of seconds and return an user-friendly
// time duration like "1d 2h 10m".
QString userFriendlyDuration(qlonglong seconds);
QString getUserIDString();
// Convert functions
QStringList toStringList(const QList<bool> &l);
QList<int> intListfromStringList(const QStringList &l);
QList<bool> boolListfromStringList(const QStringList &l);
QString accurateDoubleToString(const double &n, const int &precision);
#ifndef DISABLE_GUI
bool naturalSort(QString left, QString right, bool& result);
#endif
// Implements constant-time comparison to protect against timing attacks
// Taken from https://crackstation.net/hashing-security.htm
bool slowEquals(const QByteArray &a, const QByteArray &b);
void loadBencodedFile(const QString &filename, std::vector<char> &buffer, libtorrent::lazy_entry &entry, libtorrent::error_code &ec);
void msleep(unsigned long msecs);
}
#endif

305
src/core/net/dnsupdater.cpp Normal file
View File

@@ -0,0 +1,305 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2011 Christophe Dumez
*
* 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.
*
* Contact : chris@qbittorrent.org
*/
#include <QNetworkAccessManager>
#include <QDebug>
#include <QRegExp>
#include <QStringList>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
#include <QUrlQuery>
#endif
#include "core/logger.h"
#include "dnsupdater.h"
using namespace Net;
DNSUpdater::DNSUpdater(QObject *parent)
: QObject(parent)
, m_state(OK)
, m_service(DNS::NONE)
{
updateCredentials();
// Load saved settings from previous session
const Preferences *const pref = Preferences::instance();
m_lastIPCheckTime = pref->getDNSLastUpd();
m_lastIP = QHostAddress(pref->getDNSLastIP());
// Start IP checking timer
m_ipCheckTimer.setInterval(IP_CHECK_INTERVAL_MS);
connect(&m_ipCheckTimer, SIGNAL(timeout()), SLOT(checkPublicIP()));
m_ipCheckTimer.start();
// Check lastUpdate to avoid flooding
if (!m_lastIPCheckTime.isValid()
|| (m_lastIPCheckTime.secsTo(QDateTime::currentDateTime()) * 1000 > IP_CHECK_INTERVAL_MS)) {
checkPublicIP();
}
}
DNSUpdater::~DNSUpdater()
{
// Save lastupdate time and last ip
Preferences *const pref = Preferences::instance();
pref->setDNSLastUpd(m_lastIPCheckTime);
pref->setDNSLastIP(m_lastIP.toString());
}
void DNSUpdater::checkPublicIP()
{
Q_ASSERT(m_state == OK);
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply *)), SLOT(ipRequestFinished(QNetworkReply *)));
m_lastIPCheckTime = QDateTime::currentDateTime();
QNetworkRequest request;
request.setUrl(QUrl("http://checkip.dyndns.org"));
request.setRawHeader("User-Agent", "qBittorrent/" VERSION);
manager->get(request);
}
void DNSUpdater::ipRequestFinished(QNetworkReply *reply)
{
qDebug() << Q_FUNC_INFO;
if (reply->error()) {
// Error
qWarning() << Q_FUNC_INFO << "Error:" << reply->errorString();
}
else {
// Parse response
QRegExp ipregex("Current IP Address:\\s+([^<]+)</body>");
QString ret = reply->readAll();
if (ipregex.indexIn(ret) >= 0) {
QString ip_str = ipregex.cap(1);
qDebug() << Q_FUNC_INFO << "Regular expression captured the following IP:" << ip_str;
QHostAddress new_ip(ip_str);
if (!new_ip.isNull()) {
if (m_lastIP != new_ip) {
qDebug() << Q_FUNC_INFO << "The IP address changed, report the change to DynDNS...";
qDebug() << m_lastIP.toString() << "->" << new_ip.toString();
m_lastIP = new_ip;
updateDNSService();
}
}
else {
qWarning() << Q_FUNC_INFO << "Failed to construct a QHostAddress from the IP string";
}
}
else {
qWarning() << Q_FUNC_INFO << "Regular expression failed to capture the IP address";
}
}
// Clean up
reply->deleteLater();
sender()->deleteLater();
}
void DNSUpdater::updateDNSService()
{
qDebug() << Q_FUNC_INFO;
// Prepare request
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply *)), SLOT(ipUpdateFinished(QNetworkReply *)));
m_lastIPCheckTime = QDateTime::currentDateTime();
QNetworkRequest request;
request.setUrl(getUpdateUrl());
request.setRawHeader("User-Agent", "qBittorrent/" VERSION);
manager->get(request);
}
QUrl DNSUpdater::getUpdateUrl() const
{
QUrl url;
#ifdef QT_NO_OPENSSL
url.setScheme("http");
#else
url.setScheme("https");
#endif
url.setUserName(m_username);
url.setPassword(m_password);
Q_ASSERT(!m_lastIP.isNull());
// Service specific
switch(m_service) {
case DNS::DYNDNS:
url.setHost("members.dyndns.org");
break;
case DNS::NOIP:
url.setHost("dynupdate.no-ip.com");
break;
default:
qWarning() << "Unrecognized Dynamic DNS service!";
Q_ASSERT(0);
}
url.setPath("/nic/update");
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
url.addQueryItem("hostname", m_domain);
url.addQueryItem("myip", m_lastIP.toString());
#else
QUrlQuery urlQuery(url);
urlQuery.addQueryItem("hostname", m_domain);
urlQuery.addQueryItem("myip", m_lastIP.toString());
url.setQuery(urlQuery);
#endif
Q_ASSERT(url.isValid());
qDebug() << Q_FUNC_INFO << url.toString();
return url;
}
void DNSUpdater::ipUpdateFinished(QNetworkReply *reply)
{
if (reply->error()) {
// Error
qWarning() << Q_FUNC_INFO << "Error:" << reply->errorString();
}
else {
// Parse reply
processIPUpdateReply(reply->readAll());
}
// Clean up
reply->deleteLater();
sender()->deleteLater();
}
void DNSUpdater::processIPUpdateReply(const QString &reply)
{
Logger *const logger = Logger::instance();
qDebug() << Q_FUNC_INFO << reply;
QString code = reply.split(" ").first();
qDebug() << Q_FUNC_INFO << "Code:" << code;
if (code == "good" || code == "nochg") {
logger->addMessage(tr("Your dynamic DNS was successfully updated."), Log::INFO);
return;
}
if ((code == "911") || (code == "dnserr")) {
logger->addMessage(tr("Dynamic DNS error: The service is temporarily unavailable, it will be retried in 30 minutes."), Log::CRITICAL);
m_lastIP.clear();
// It will retry in 30 minutes because the timer was not stopped
return;
}
// Everything bellow is an error, stop updating until the user updates something
m_ipCheckTimer.stop();
m_lastIP.clear();
if (code == "nohost") {
logger->addMessage(tr("Dynamic DNS error: hostname supplied does not exist under specified account."), Log::CRITICAL);
m_state = INVALID_CREDS;
return;
}
if (code == "badauth") {
logger->addMessage(tr("Dynamic DNS error: Invalid username/password."), Log::CRITICAL);
m_state = INVALID_CREDS;
return;
}
if (code == "badagent") {
logger->addMessage(tr("Dynamic DNS error: qBittorrent was blacklisted by the service, please report a bug at http://bugs.qbittorrent.org."),
Log::CRITICAL);
m_state = FATAL;
return;
}
if (code == "!donator") {
logger->addMessage(tr("Dynamic DNS error: %1 was returned by the service, please report a bug at http://bugs.qbittorrent.org.").arg("!donator"),
Log::CRITICAL);
m_state = FATAL;
return;
}
if (code == "abuse") {
logger->addMessage(tr("Dynamic DNS error: Your username was blocked due to abuse."), Log::CRITICAL);
m_state = FATAL;
return;
}
}
void DNSUpdater::updateCredentials()
{
if (m_state == FATAL) return;
Preferences *const pref = Preferences::instance();
Logger *const logger = Logger::instance();
bool change = false;
// Get DNS service information
if (m_service != pref->getDynDNSService()) {
m_service = pref->getDynDNSService();
change = true;
}
if (m_domain != pref->getDynDomainName()) {
m_domain = pref->getDynDomainName();
QRegExp domain_regex("^(?:(?!\\d|-)[a-zA-Z0-9\\-]{1,63}\\.)+[a-zA-Z]{2,}$");
if (domain_regex.indexIn(m_domain) < 0) {
logger->addMessage(tr("Dynamic DNS error: supplied domain name is invalid."), Log::CRITICAL);
m_lastIP.clear();
m_ipCheckTimer.stop();
m_state = INVALID_CREDS;
return;
}
change = true;
}
if (m_username != pref->getDynDNSUsername()) {
m_username = pref->getDynDNSUsername();
if (m_username.length() < 4) {
logger->addMessage(tr("Dynamic DNS error: supplied username is too short."), Log::CRITICAL);
m_lastIP.clear();
m_ipCheckTimer.stop();
m_state = INVALID_CREDS;
return;
}
change = true;
}
if (m_password != pref->getDynDNSPassword()) {
m_password = pref->getDynDNSPassword();
if (m_password.length() < 4) {
logger->addMessage(tr("Dynamic DNS error: supplied password is too short."), Log::CRITICAL);
m_lastIP.clear();
m_ipCheckTimer.stop();
m_state = INVALID_CREDS;
return;
}
change = true;
}
if ((m_state == INVALID_CREDS) && change) {
m_state = OK; // Try again
m_ipCheckTimer.start();
checkPublicIP();
}
}
QUrl DNSUpdater::getRegistrationUrl(int service)
{
switch(service) {
case DNS::DYNDNS:
return QUrl("https://www.dyndns.com/account/services/hosts/add.html");
case DNS::NOIP:
return QUrl("http://www.no-ip.com/services/managed_dns/free_dynamic_dns.html");
default:
Q_ASSERT(0);
}
return QUrl();
}

View File

@@ -36,46 +36,55 @@
#include <QNetworkReply>
#include <QDateTime>
#include <QTimer>
#include "preferences.h"
#include "core/preferences.h"
/*!
* Based on http://www.dyndns.com/developers/specs/
*/
class DNSUpdater : public QObject
{
Q_OBJECT
public:
explicit DNSUpdater(QObject *parent = 0);
~DNSUpdater();
static QUrl getRegistrationUrl(int service);
namespace Net
{
// Based on http://www.dyndns.com/developers/specs/
class DNSUpdater : public QObject
{
Q_OBJECT
public slots:
void updateCredentials();
public:
explicit DNSUpdater(QObject *parent = 0);
~DNSUpdater();
private slots:
void checkPublicIP();
void ipRequestFinished(QNetworkReply* reply);
void updateDNSService();
void ipUpdateFinished(QNetworkReply* reply);
static QUrl getRegistrationUrl(int service);
private:
QUrl getUpdateUrl() const;
void processIPUpdateReply(const QString &reply);
public slots:
void updateCredentials();
private:
QHostAddress m_lastIP;
QDateTime m_lastIPCheckTime;
QTimer m_ipCheckTimer;
int m_state;
// Service creds
DNS::Service m_service;
QString m_domain;
QString m_username;
QString m_password;
private slots:
void checkPublicIP();
void ipRequestFinished(QNetworkReply *reply);
void updateDNSService();
void ipUpdateFinished(QNetworkReply *reply);
private:
static const int IP_CHECK_INTERVAL_MS = 1800000; // 30 min
enum State { OK, INVALID_CREDS, FATAL };
};
private:
QUrl getUpdateUrl() const;
void processIPUpdateReply(const QString &reply);
private:
QHostAddress m_lastIP;
QDateTime m_lastIPCheckTime;
QTimer m_ipCheckTimer;
int m_state;
// Service creds
DNS::Service m_service;
QString m_domain;
QString m_username;
QString m_password;
private:
static const int IP_CHECK_INTERVAL_MS = 1800000; // 30 min
enum State
{
OK,
INVALID_CREDS,
FATAL
};
};
}
#endif // DNSUPDATER_H

View File

@@ -0,0 +1,248 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* 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 <QTemporaryFile>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkProxy>
#include <QNetworkCookie>
#include <QUrl>
#include <QDebug>
#include "core/utils/fs.h"
#include "core/utils/gzip.h"
#include "core/utils/misc.h"
#include "downloadmanager.h"
#include "downloadhandler.h"
static QString errorCodeToString(QNetworkReply::NetworkError status);
using namespace Net;
DownloadHandler::DownloadHandler(QNetworkReply *reply, DownloadManager *manager, bool saveToFile, qint64 limit, bool handleRedirectToMagnet)
: QObject(manager)
, m_reply(reply)
, m_manager(manager)
, m_saveToFile(saveToFile)
, m_sizeLimit(limit)
, m_handleRedirectToMagnet(handleRedirectToMagnet)
, m_url(reply->url().toString())
{
init();
}
DownloadHandler::~DownloadHandler()
{
if (m_reply)
delete m_reply;
}
// Returns original url
QString DownloadHandler::url() const
{
return m_url;
}
void DownloadHandler::processFinishedDownload()
{
QString url = m_reply->url().toString();
qDebug("Download finished: %s", qPrintable(url));
// Check if the request was successful
if (m_reply->error() != QNetworkReply::NoError) {
// Failure
qDebug("Download failure (%s), reason: %s", qPrintable(url), qPrintable(errorCodeToString(m_reply->error())));
emit downloadFailed(m_url, errorCodeToString(m_reply->error()));
this->deleteLater();
}
else {
// Check if the server ask us to redirect somewhere else
const QVariant redirection = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (redirection.isValid()) {
// We should redirect
handleRedirection(redirection.toUrl());
}
else {
// Success
QByteArray replyData = m_reply->readAll();
if (m_reply->rawHeader("Content-Encoding") == "gzip") {
// uncompress gzip reply
Utils::Gzip::uncompress(replyData, replyData);
}
if (m_saveToFile) {
QString filePath;
if (saveToFile(replyData, filePath))
emit downloadFinished(m_url, filePath);
else
emit downloadFailed(m_url, tr("I/O Error"));
}
else {
emit downloadFinished(m_url, replyData);
}
this->deleteLater();
}
}
}
void DownloadHandler::checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal)
{
QString msg = tr("The file size is %1. It exceeds the download limit of %2.");
if (bytesTotal > 0) {
// Total number of bytes is available
if (bytesTotal > m_sizeLimit) {
m_reply->abort();
emit downloadFailed(m_url, msg.arg(Utils::Misc::friendlyUnit(bytesTotal)).arg(Utils::Misc::friendlyUnit(m_sizeLimit)));
}
else {
disconnect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(checkDownloadSize(qint64, qint64)));
}
}
else if (bytesReceived > m_sizeLimit) {
m_reply->abort();
emit downloadFailed(m_url, msg.arg(Utils::Misc::friendlyUnit(bytesReceived)).arg(Utils::Misc::friendlyUnit(m_sizeLimit)));
}
}
void DownloadHandler::init()
{
m_reply->setParent(this);
if (m_sizeLimit > 0)
connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(checkDownloadSize(qint64, qint64)));
connect(m_reply, SIGNAL(finished()), this, SLOT(processFinishedDownload()));
}
bool DownloadHandler::saveToFile(const QByteArray &replyData, QString &filePath)
{
QTemporaryFile *tmpfile = new QTemporaryFile;
if (!tmpfile->open()) {
delete tmpfile;
return false;
}
tmpfile->setAutoRemove(false);
filePath = tmpfile->fileName();
qDebug("Temporary filename is: %s", qPrintable(filePath));
if (m_reply->isOpen() || m_reply->open(QIODevice::ReadOnly)) {
tmpfile->write(replyData);
tmpfile->close();
// XXX: tmpfile needs to be deleted on Windows before using the file
// or it will complain that the file is used by another process.
delete tmpfile;
return true;
}
else {
delete tmpfile;
Utils::Fs::forceRemove(filePath);
}
return false;
}
void DownloadHandler::handleRedirection(QUrl newUrl)
{
// Resolve relative urls
if (newUrl.isRelative())
newUrl = m_reply->url().resolved(newUrl);
const QString newUrlString = newUrl.toString();
qDebug("Redirecting from %s to %s", qPrintable(m_reply->url().toString()), qPrintable(newUrlString));
// Redirect to magnet workaround
if (newUrlString.startsWith("magnet:", Qt::CaseInsensitive)) {
qDebug("Magnet redirect detected.");
m_reply->abort();
if (m_handleRedirectToMagnet)
emit redirectedToMagnet(m_url, newUrlString);
else
emit downloadFailed(m_url, tr("Unexpected redirect to magnet URI."));
this->deleteLater();
}
else {
DownloadHandler *tmp = m_manager->downloadUrl(newUrlString, m_saveToFile, m_sizeLimit, m_handleRedirectToMagnet);
m_reply->deleteLater();
m_reply = tmp->m_reply;
init();
tmp->m_reply = 0;
delete tmp;
}
}
QString errorCodeToString(QNetworkReply::NetworkError status)
{
switch(status) {
case QNetworkReply::HostNotFoundError:
return QObject::tr("The remote host name was not found (invalid hostname)");
case QNetworkReply::OperationCanceledError:
return QObject::tr("The operation was canceled");
case QNetworkReply::RemoteHostClosedError:
return QObject::tr("The remote server closed the connection prematurely, before the entire reply was received and processed");
case QNetworkReply::TimeoutError:
return QObject::tr("The connection to the remote server timed out");
case QNetworkReply::SslHandshakeFailedError:
return QObject::tr("SSL/TLS handshake failed");
case QNetworkReply::ConnectionRefusedError:
return QObject::tr("The remote server refused the connection");
case QNetworkReply::ProxyConnectionRefusedError:
return QObject::tr("The connection to the proxy server was refused");
case QNetworkReply::ProxyConnectionClosedError:
return QObject::tr("The proxy server closed the connection prematurely");
case QNetworkReply::ProxyNotFoundError:
return QObject::tr("The proxy host name was not found");
case QNetworkReply::ProxyTimeoutError:
return QObject::tr("The connection to the proxy timed out or the proxy did not reply in time to the request sent");
case QNetworkReply::ProxyAuthenticationRequiredError:
return QObject::tr("The proxy requires authentication in order to honor the request but did not accept any credentials offered");
case QNetworkReply::ContentAccessDenied:
return QObject::tr("The access to the remote content was denied (401)");
case QNetworkReply::ContentOperationNotPermittedError:
return QObject::tr("The operation requested on the remote content is not permitted");
case QNetworkReply::ContentNotFoundError:
return QObject::tr("The remote content was not found at the server (404)");
case QNetworkReply::AuthenticationRequiredError:
return QObject::tr("The remote server requires authentication to serve the content but the credentials provided were not accepted");
case QNetworkReply::ProtocolUnknownError:
return QObject::tr("The Network Access API cannot honor the request because the protocol is not known");
case QNetworkReply::ProtocolInvalidOperationError:
return QObject::tr("The requested operation is invalid for this protocol");
case QNetworkReply::UnknownNetworkError:
return QObject::tr("An unknown network-related error was detected");
case QNetworkReply::UnknownProxyError:
return QObject::tr("An unknown proxy-related error was detected");
case QNetworkReply::UnknownContentError:
return QObject::tr("An unknown error related to the remote content was detected");
case QNetworkReply::ProtocolFailure:
return QObject::tr("A breakdown in protocol was detected");
default:
return QObject::tr("Unknown error");
}
}

View File

@@ -1,6 +1,7 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2006 Christophe Dumez
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -24,54 +25,55 @@
* 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 DOWNLOADTHREAD_H
#define DOWNLOADTHREAD_H
#ifndef NET_DOWNLOADHANDLER_H
#define NET_DOWNLOADHANDLER_H
#include <QNetworkReply>
#include <QNetworkCookie>
#include <QObject>
#include <QHash>
#include <QSslError>
#include <zlib.h>
QT_BEGIN_NAMESPACE
class QNetworkAccessManager;
class QNetworkReply;
class QUrl;
QT_END_NAMESPACE
class DownloadThread : public QObject {
Q_OBJECT
namespace Net
{
class DownloadManager;
public:
DownloadThread(QObject* parent = 0);
QNetworkReply* downloadUrl(const QString &url, const QList<QNetworkCookie>& cookies = QList<QNetworkCookie>());
void downloadTorrentUrl(const QString &url, const QList<QNetworkCookie>& cookies = QList<QNetworkCookie>());
//void setProxy(QString IP, int port, QString username, QString password);
class DownloadHandler : public QObject
{
Q_OBJECT
signals:
void downloadFinished(const QString &url, const QString &file_path);
void downloadFailure(const QString &url, const QString &reason);
void magnetRedirect(const QString &url_new, const QString &url_old);
public:
DownloadHandler(QNetworkReply *reply, DownloadManager *manager, bool saveToFile = false, qint64 limit = 0, bool handleRedirectToMagnet = false);
~DownloadHandler();
private slots:
void processDlFinished(QNetworkReply* reply);
void checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal);
#ifndef QT_NO_OPENSSL
void ignoreSslErrors(QNetworkReply*,const QList<QSslError>&);
#endif
QString url() const;
private:
static QByteArray gUncompress(Bytef *inData, size_t len);
QString errorCodeToString(QNetworkReply::NetworkError status);
void applyProxySettings();
signals:
void downloadFinished(const QString &url, const QByteArray &data);
void downloadFinished(const QString &url, const QString &filePath);
void downloadFailed(const QString &url, const QString &reason);
void redirectedToMagnet(const QString &url, const QString &magnetUri);
private:
QNetworkAccessManager m_networkManager;
QHash<QString, QString> m_redirectMapping;
private slots:
void processFinishedDownload();
void checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal);
};
private:
void init();
bool saveToFile(const QByteArray &replyData, QString &filePath);
void handleRedirection(QUrl newUrl);
#endif
QNetworkReply *m_reply;
DownloadManager *m_manager;
bool m_saveToFile;
qint64 m_sizeLimit;
bool m_handleRedirectToMagnet;
QString m_url;
};
}
#endif // NET_DOWNLOADHANDLER_H

View File

@@ -0,0 +1,151 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* 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 <QNetworkRequest>
#include <QNetworkProxy>
#include <QNetworkCookieJar>
#include <QNetworkReply>
#include <QNetworkCookie>
#include <QSslError>
#include <QUrl>
#include <QDebug>
#include "core/preferences.h"
#include "downloadhandler.h"
#include "downloadmanager.h"
using namespace Net;
DownloadManager *DownloadManager::m_instance = 0;
DownloadManager::DownloadManager(QObject *parent)
: QObject(parent)
{
#ifndef QT_NO_OPENSSL
connect(&m_networkManager, SIGNAL(sslErrors(QNetworkReply *, QList<QSslError>)), this, SLOT(ignoreSslErrors(QNetworkReply *, QList<QSslError>)));
#endif
}
DownloadManager::~DownloadManager()
{
}
void DownloadManager::initInstance()
{
if (!m_instance)
m_instance = new DownloadManager;
}
void DownloadManager::freeInstance()
{
if (m_instance) {
delete m_instance;
m_instance = 0;
}
}
DownloadManager *DownloadManager::instance()
{
return m_instance;
}
DownloadHandler *DownloadManager::downloadUrl(const QString &url, bool saveToFile, qint64 limit, bool handleRedirectToMagnet)
{
// Update proxy settings
applyProxySettings();
// Process download request
qDebug("url is %s", qPrintable(url));
const QUrl qurl = QUrl::fromEncoded(url.toUtf8());
QNetworkRequest request(qurl);
// Spoof Firefox 38 user agent to avoid web server banning
request.setRawHeader("User-Agent", "Mozilla/5.0 (X11; Linux i686; rv:38.0) Gecko/20100101 Firefox/38.0");
// Spoof HTTP Referer to allow adding torrent link from Torcache/KickAssTorrents
request.setRawHeader("Referer", request.url().toEncoded().data());
qDebug("Downloading %s...", request.url().toEncoded().data());
// accept gzip
request.setRawHeader("Accept-Encoding", "gzip");
return new DownloadHandler(m_networkManager.get(request), this, saveToFile, limit, handleRedirectToMagnet);
}
QList<QNetworkCookie> DownloadManager::cookiesForUrl(const QString &url) const
{
return m_networkManager.cookieJar()->cookiesForUrl(url);
}
bool DownloadManager::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url)
{
qDebug("Setting %d cookies for url: %s", cookieList.size(), qPrintable(url.toString()));
return m_networkManager.cookieJar()->setCookiesFromUrl(cookieList, url);
}
void DownloadManager::applyProxySettings()
{
QNetworkProxy proxy;
const Preferences* const pref = Preferences::instance();
if (pref->isProxyEnabled() && !pref->isProxyOnlyForTorrents()) {
// Proxy enabled
proxy.setHostName(pref->getProxyIp());
proxy.setPort(pref->getProxyPort());
// Default proxy type is HTTP, we must change if it is SOCKS5
const int proxyType = pref->getProxyType();
if ((proxyType == Proxy::SOCKS5) || (proxyType == Proxy::SOCKS5_PW)) {
qDebug() << Q_FUNC_INFO << "using SOCKS proxy";
proxy.setType(QNetworkProxy::Socks5Proxy);
}
else {
qDebug() << Q_FUNC_INFO << "using HTTP proxy";
proxy.setType(QNetworkProxy::HttpProxy);
}
// Authentication?
if (pref->isProxyAuthEnabled()) {
qDebug("Proxy requires authentication, authenticating");
proxy.setUser(pref->getProxyUsername());
proxy.setPassword(pref->getProxyPassword());
}
}
else {
proxy.setType(QNetworkProxy::NoProxy);
}
m_networkManager.setProxy(proxy);
}
#ifndef QT_NO_OPENSSL
void DownloadManager::ignoreSslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
{
Q_UNUSED(errors)
// Ignore all SSL errors
reply->ignoreSslErrors();
}
#endif

View File

@@ -0,0 +1,76 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#ifndef NET_DOWNLOADMANAGER_H
#define NET_DOWNLOADMANAGER_H
#include <QObject>
#include <QNetworkAccessManager>
QT_BEGIN_NAMESPACE
class QNetworkReply;
class QNetworkCookie;
class QSslError;
class QUrl;
QT_END_NAMESPACE
namespace Net
{
class DownloadHandler;
class DownloadManager : public QObject
{
Q_OBJECT
public:
static void initInstance();
static void freeInstance();
static DownloadManager *instance();
DownloadHandler *downloadUrl(const QString &url, bool saveToFile = false, qint64 limit = 0, bool handleRedirectToMagnet = false);
QList<QNetworkCookie> cookiesForUrl(const QString &url) const;
bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url);
private slots:
#ifndef QT_NO_OPENSSL
void ignoreSslErrors(QNetworkReply *,const QList<QSslError> &);
#endif
private:
DownloadManager(QObject *parent = 0);
~DownloadManager();
void applyProxySettings();
static DownloadManager *m_instance;
QNetworkAccessManager m_networkManager;
};
}
#endif // NET_DOWNLOADMANAGER_H

View File

@@ -0,0 +1,461 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
*
* 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 <QDebug>
#include <QFile>
#include <QDir>
#include <QHostAddress>
#include <QDateTime>
#include "core/logger.h"
#include "core/preferences.h"
#include "core/utils/fs.h"
#include "core/utils/gzip.h"
#include "downloadmanager.h"
#include "downloadhandler.h"
#include "private/geoipdatabase.h"
#include "geoipmanager.h"
static const char DATABASE_URL[] = "http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz";
static const char GEOIP_FOLDER[] = "GeoIP";
static const char GEOIP_FILENAME[] = "GeoLite2-Country.mmdb";
static const int CACHE_SIZE = 1000;
static const int UPDATE_INTERVAL = 30; // Days between database updates
using namespace Net;
// GeoIPManager
GeoIPManager *GeoIPManager::m_instance = 0;
GeoIPManager::GeoIPManager()
: m_enabled(false)
, m_geoIPDatabase(0)
{
configure();
connect(Preferences::instance(), SIGNAL(changed()), SLOT(configure()));
}
GeoIPManager::~GeoIPManager()
{
if (m_geoIPDatabase)
delete m_geoIPDatabase;
}
void GeoIPManager::initInstance()
{
if (!m_instance)
m_instance = new GeoIPManager;
}
void GeoIPManager::freeInstance()
{
if (m_instance) {
delete m_instance;
m_instance = 0;
}
}
GeoIPManager *GeoIPManager::instance()
{
return m_instance;
}
void GeoIPManager::loadDatabase()
{
if (m_geoIPDatabase) {
delete m_geoIPDatabase;
m_geoIPDatabase = 0;
}
QString filepath = Utils::Fs::expandPathAbs(
QString("%1%2/%3").arg(Utils::Fs::QDesktopServicesDataLocation())
.arg(GEOIP_FOLDER).arg(GEOIP_FILENAME));
QString error;
m_geoIPDatabase = GeoIPDatabase::load(filepath, error);
if (m_geoIPDatabase)
Logger::instance()->addMessage(tr("GeoIP database loaded. Type: %1. Build time: %2.")
.arg(m_geoIPDatabase->type()).arg(m_geoIPDatabase->buildEpoch().toString()),
Log::INFO);
else
Logger::instance()->addMessage(tr("Couldn't load GeoIP database. Reason: %1").arg(error), Log::WARNING);
manageDatabaseUpdate();
}
void GeoIPManager::manageDatabaseUpdate()
{
if (!m_geoIPDatabase || (m_geoIPDatabase->buildEpoch().daysTo(QDateTime::currentDateTimeUtc()) >= UPDATE_INTERVAL))
downloadDatabaseFile();
}
void GeoIPManager::downloadDatabaseFile()
{
DownloadHandler *handler = DownloadManager::instance()->downloadUrl(DATABASE_URL);
connect(handler, SIGNAL(downloadFinished(QString, QByteArray)), SLOT(downloadFinished(QString, QByteArray)));
connect(handler, SIGNAL(downloadFailed(QString, QString)), SLOT(downloadFailed(QString, QString)));
}
QString GeoIPManager::lookup(const QHostAddress &hostAddr) const
{
if (m_enabled && m_geoIPDatabase)
return m_geoIPDatabase->lookup(hostAddr);
return QString();
}
// http://www.iso.org/iso/country_codes/iso_3166_code_lists/english_country_names_and_code_elements.htm
QString GeoIPManager::CountryName(const QString &countryISOCode)
{
static QHash<QString, QString> countries;
static bool initialized = false;
if (!initialized) {
countries[QString()] = tr("N/A");
countries["AP"] = tr("Asia/Pacific Region");
countries["EU"] = tr("Europe");
countries["AD"] = tr("Andorra");
countries["AE"] = tr("United Arab Emirates");
countries["AF"] = tr("Afghanistan");
countries["AG"] = tr("Antigua and Barbuda");
countries["AI"] = tr("Anguilla");
countries["AL"] = tr("Albania");
countries["AM"] = tr("Armenia");
countries["AN"] = tr("Netherlands Antilles");
countries["AO"] = tr("Angola");
countries["AQ"] = tr("Antarctica");
countries["AR"] = tr("Argentina");
countries["AS"] = tr("American Samoa");
countries["AT"] = tr("Austria");
countries["AU"] = tr("Australia");
countries["AW"] = tr("Aruba");
countries["AZ"] = tr("Azerbaijan");
countries["BA"] = tr("Bosnia and Herzegovina");
countries["BB"] = tr("Barbados");
countries["BD"] = tr("Bangladesh");
countries["BE"] = tr("Belgium");
countries["BF"] = tr("Burkina Faso");
countries["BG"] = tr("Bulgaria");
countries["BH"] = tr("Bahrain");
countries["BI"] = tr("Burundi");
countries["BJ"] = tr("Benin");
countries["BM"] = tr("Bermuda");
countries["BN"] = tr("Brunei Darussalam");
countries["BO"] = tr("Bolivia");
countries["BR"] = tr("Brazil");
countries["BS"] = tr("Bahamas");
countries["BT"] = tr("Bhutan");
countries["BV"] = tr("Bouvet Island");
countries["BW"] = tr("Botswana");
countries["BY"] = tr("Belarus");
countries["BZ"] = tr("Belize");
countries["CA"] = tr("Canada");
countries["CC"] = tr("Cocos (Keeling) Islands");
countries["CD"] = tr("Congo, The Democratic Republic of the");
countries["CF"] = tr("Central African Republic");
countries["CG"] = tr("Congo");
countries["CH"] = tr("Switzerland");
countries["CI"] = tr("Cote D'Ivoire");
countries["CK"] = tr("Cook Islands");
countries["CL"] = tr("Chile");
countries["CM"] = tr("Cameroon");
countries["CN"] = tr("China");
countries["CO"] = tr("Colombia");
countries["CR"] = tr("Costa Rica");
countries["CU"] = tr("Cuba");
countries["CV"] = tr("Cape Verde");
countries["CX"] = tr("Christmas Island");
countries["CY"] = tr("Cyprus");
countries["CZ"] = tr("Czech Republic");
countries["DE"] = tr("Germany");
countries["DJ"] = tr("Djibouti");
countries["DK"] = tr("Denmark");
countries["DM"] = tr("Dominica");
countries["DO"] = tr("Dominican Republic");
countries["DZ"] = tr("Algeria");
countries["EC"] = tr("Ecuador");
countries["EE"] = tr("Estonia");
countries["EG"] = tr("Egypt");
countries["EH"] = tr("Western Sahara");
countries["ER"] = tr("Eritrea");
countries["ES"] = tr("Spain");
countries["ET"] = tr("Ethiopia");
countries["FI"] = tr("Finland");
countries["FJ"] = tr("Fiji");
countries["FK"] = tr("Falkland Islands (Malvinas)");
countries["FM"] = tr("Micronesia, Federated States of");
countries["FO"] = tr("Faroe Islands");
countries["FR"] = tr("France");
countries["FX"] = tr("France, Metropolitan");
countries["GA"] = tr("Gabon");
countries["GB"] = tr("United Kingdom");
countries["GD"] = tr("Grenada");
countries["GE"] = tr("Georgia");
countries["GF"] = tr("French Guiana");
countries["GH"] = tr("Ghana");
countries["GI"] = tr("Gibraltar");
countries["GL"] = tr("Greenland");
countries["GM"] = tr("Gambia");
countries["GN"] = tr("Guinea");
countries["GP"] = tr("Guadeloupe");
countries["GQ"] = tr("Equatorial Guinea");
countries["GR"] = tr("Greece");
countries["GS"] = tr("South Georgia and the South Sandwich Islands");
countries["GT"] = tr("Guatemala");
countries["GU"] = tr("Guam");
countries["GW"] = tr("Guinea-Bissau");
countries["GY"] = tr("Guyana");
countries["HK"] = tr("Hong Kong");
countries["HM"] = tr("Heard Island and McDonald Islands");
countries["HN"] = tr("Honduras");
countries["HR"] = tr("Croatia");
countries["HT"] = tr("Haiti");
countries["HU"] = tr("Hungary");
countries["ID"] = tr("Indonesia");
countries["IE"] = tr("Ireland");
countries["IL"] = tr("Israel");
countries["IN"] = tr("India");
countries["IO"] = tr("British Indian Ocean Territory");
countries["IQ"] = tr("Iraq");
countries["IR"] = tr("Iran, Islamic Republic of");
countries["IS"] = tr("Iceland");
countries["IT"] = tr("Italy");
countries["JM"] = tr("Jamaica");
countries["JO"] = tr("Jordan");
countries["JP"] = tr("Japan");
countries["KE"] = tr("Kenya");
countries["KG"] = tr("Kyrgyzstan");
countries["KH"] = tr("Cambodia");
countries["KI"] = tr("Kiribati");
countries["KM"] = tr("Comoros");
countries["KN"] = tr("Saint Kitts and Nevis");
countries["KP"] = tr("Korea, Democratic People's Republic of");
countries["KR"] = tr("Korea, Republic of");
countries["KW"] = tr("Kuwait");
countries["KY"] = tr("Cayman Islands");
countries["KZ"] = tr("Kazakhstan");
countries["LA"] = tr("Lao People's Democratic Republic");
countries["LB"] = tr("Lebanon");
countries["LC"] = tr("Saint Lucia");
countries["LI"] = tr("Liechtenstein");
countries["LK"] = tr("Sri Lanka");
countries["LR"] = tr("Liberia");
countries["LS"] = tr("Lesotho");
countries["LT"] = tr("Lithuania");
countries["LU"] = tr("Luxembourg");
countries["LV"] = tr("Latvia");
countries["LY"] = tr("Libyan Arab Jamahiriya");
countries["MA"] = tr("Morocco");
countries["MC"] = tr("Monaco");
countries["MD"] = tr("Moldova, Republic of");
countries["MG"] = tr("Madagascar");
countries["MH"] = tr("Marshall Islands");
countries["MK"] = tr("Macedonia");
countries["ML"] = tr("Mali");
countries["MM"] = tr("Myanmar");
countries["MN"] = tr("Mongolia");
countries["MO"] = tr("Macau");
countries["MP"] = tr("Northern Mariana Islands");
countries["MQ"] = tr("Martinique");
countries["MR"] = tr("Mauritania");
countries["MS"] = tr("Montserrat");
countries["MT"] = tr("Malta");
countries["MU"] = tr("Mauritius");
countries["MV"] = tr("Maldives");
countries["MW"] = tr("Malawi");
countries["MX"] = tr("Mexico");
countries["MY"] = tr("Malaysia");
countries["MZ"] = tr("Mozambique");
countries["NA"] = tr("Namibia");
countries["NC"] = tr("New Caledonia");
countries["NE"] = tr("Niger");
countries["NF"] = tr("Norfolk Island");
countries["NG"] = tr("Nigeria");
countries["NI"] = tr("Nicaragua");
countries["NL"] = tr("Netherlands");
countries["NO"] = tr("Norway");
countries["NP"] = tr("Nepal");
countries["NR"] = tr("Nauru");
countries["NU"] = tr("Niue");
countries["NZ"] = tr("New Zealand");
countries["OM"] = tr("Oman");
countries["PA"] = tr("Panama");
countries["PE"] = tr("Peru");
countries["PF"] = tr("French Polynesia");
countries["PG"] = tr("Papua New Guinea");
countries["PH"] = tr("Philippines");
countries["PK"] = tr("Pakistan");
countries["PL"] = tr("Poland");
countries["PM"] = tr("Saint Pierre and Miquelon");
countries["PN"] = tr("Pitcairn Islands");
countries["PR"] = tr("Puerto Rico");
countries["PS"] = tr("Palestinian Territory");
countries["PT"] = tr("Portugal");
countries["PW"] = tr("Palau");
countries["PY"] = tr("Paraguay");
countries["QA"] = tr("Qatar");
countries["RE"] = tr("Reunion");
countries["RO"] = tr("Romania");
countries["RU"] = tr("Russian Federation");
countries["RW"] = tr("Rwanda");
countries["SA"] = tr("Saudi Arabia");
countries["SB"] = tr("Solomon Islands");
countries["SC"] = tr("Seychelles");
countries["SD"] = tr("Sudan");
countries["SE"] = tr("Sweden");
countries["SG"] = tr("Singapore");
countries["SH"] = tr("Saint Helena");
countries["SI"] = tr("Slovenia");
countries["SJ"] = tr("Svalbard and Jan Mayen");
countries["SK"] = tr("Slovakia");
countries["SL"] = tr("Sierra Leone");
countries["SM"] = tr("San Marino");
countries["SN"] = tr("Senegal");
countries["SO"] = tr("Somalia");
countries["SR"] = tr("Suriname");
countries["ST"] = tr("Sao Tome and Principe");
countries["SV"] = tr("El Salvador");
countries["SY"] = tr("Syrian Arab Republic");
countries["SZ"] = tr("Swaziland");
countries["TC"] = tr("Turks and Caicos Islands");
countries["TD"] = tr("Chad");
countries["TF"] = tr("French Southern Territories");
countries["TG"] = tr("Togo");
countries["TH"] = tr("Thailand");
countries["TJ"] = tr("Tajikistan");
countries["TK"] = tr("Tokelau");
countries["TM"] = tr("Turkmenistan");
countries["TN"] = tr("Tunisia");
countries["TO"] = tr("Tonga");
countries["TL"] = tr("Timor-Leste");
countries["TR"] = tr("Turkey");
countries["TT"] = tr("Trinidad and Tobago");
countries["TV"] = tr("Tuvalu");
countries["TW"] = tr("Taiwan");
countries["TZ"] = tr("Tanzania, United Republic of");
countries["UA"] = tr("Ukraine");
countries["UG"] = tr("Uganda");
countries["UM"] = tr("United States Minor Outlying Islands");
countries["US"] = tr("United States");
countries["UY"] = tr("Uruguay");
countries["UZ"] = tr("Uzbekistan");
countries["VA"] = tr("Holy See (Vatican City State)");
countries["VC"] = tr("Saint Vincent and the Grenadines");
countries["VE"] = tr("Venezuela");
countries["VG"] = tr("Virgin Islands, British");
countries["VI"] = tr("Virgin Islands, U.S.");
countries["VN"] = tr("Vietnam");
countries["VU"] = tr("Vanuatu");
countries["WF"] = tr("Wallis and Futuna");
countries["WS"] = tr("Samoa");
countries["YE"] = tr("Yemen");
countries["YT"] = tr("Mayotte");
countries["RS"] = tr("Serbia");
countries["ZA"] = tr("South Africa");
countries["ZM"] = tr("Zambia");
countries["ME"] = tr("Montenegro");
countries["ZW"] = tr("Zimbabwe");
countries["A1"] = tr("Anonymous Proxy");
countries["A2"] = tr("Satellite Provider");
countries["O1"] = tr("Other");
countries["AX"] = tr("Aland Islands");
countries["GG"] = tr("Guernsey");
countries["IM"] = tr("Isle of Man");
countries["JE"] = tr("Jersey");
countries["BL"] = tr("Saint Barthelemy");
countries["MF"] = tr("Saint Martin");
initialized = true;
}
return countries.value(countryISOCode, tr("N/A"));
}
void GeoIPManager::configure()
{
const bool enabled = Preferences::instance()->resolvePeerCountries();
if (m_enabled != enabled) {
m_enabled = enabled;
if (m_enabled && !m_geoIPDatabase) {
loadDatabase();
}
else if (!m_enabled && m_geoIPDatabase) {
delete m_geoIPDatabase;
m_geoIPDatabase = 0;
}
}
}
void GeoIPManager::downloadFinished(const QString &url, QByteArray data)
{
Q_UNUSED(url);
if (!Utils::Gzip::uncompress(data, data)) {
Logger::instance()->addMessage(tr("Could not uncompress GeoIP database file."), Log::WARNING);
return;
}
QString error;
GeoIPDatabase *geoIPDatabase = GeoIPDatabase::load(data, error);
if (geoIPDatabase) {
if (!m_geoIPDatabase || (geoIPDatabase->buildEpoch() > m_geoIPDatabase->buildEpoch())) {
if (m_geoIPDatabase)
delete m_geoIPDatabase;
m_geoIPDatabase = geoIPDatabase;
Logger::instance()->addMessage(tr("GeoIP database loaded. Type: %1. Build time: %2.")
.arg(m_geoIPDatabase->type()).arg(m_geoIPDatabase->buildEpoch().toString()),
Log::INFO);
QString targetPath = Utils::Fs::expandPathAbs(
Utils::Fs::QDesktopServicesDataLocation() + GEOIP_FOLDER);
if (!QDir(targetPath).exists())
QDir().mkpath(targetPath);
QFile targetFile(QString("%1/%2").arg(targetPath).arg(GEOIP_FILENAME));
if (!targetFile.open(QFile::WriteOnly) || (targetFile.write(data) == -1)) {
Logger::instance()->addMessage(
tr("Couldn't save downloaded GeoIP database file."), Log::WARNING);
}
else {
Logger::instance()->addMessage(tr("Successfully updated GeoIP database."), Log::INFO);
}
}
else {
delete geoIPDatabase;
}
}
else {
Logger::instance()->addMessage(tr("Couldn't load GeoIP database. Reason: %1").arg(error), Log::WARNING);
}
}
void GeoIPManager::downloadFailed(const QString &url, const QString &reason)
{
Q_UNUSED(url);
Logger::instance()->addMessage(tr("Couldn't download GeoIP database file. Reason: %1").arg(reason), Log::WARNING);
}

View File

@@ -0,0 +1,76 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#ifndef NET_GEOIPMANAGER_H
#define NET_GEOIPMANAGER_H
#include <QObject>
#include <QCache>
class QHostAddress;
class QString;
class GeoIPDatabase;
namespace Net
{
class GeoIPManager : public QObject
{
Q_OBJECT
public:
static void initInstance();
static void freeInstance();
static GeoIPManager *instance();
QString lookup(const QHostAddress &hostAddr) const;
static QString CountryName(const QString &countryISOCode);
private slots:
void configure();
void downloadFinished(const QString &url, QByteArray data);
void downloadFailed(const QString &url, const QString &reason);
private:
GeoIPManager();
~GeoIPManager();
void loadDatabase();
void manageDatabaseUpdate();
void downloadDatabaseFile();
bool m_enabled;
GeoIPDatabase *m_geoIPDatabase;
static GeoIPManager *m_instance;
};
}
#endif // NET_GEOIPMANAGER_H

View File

@@ -0,0 +1,122 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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 <QDebug>
#include <libtorrent/session.hpp>
#include "core/logger.h"
#include "core/preferences.h"
#include "portforwarder.h"
namespace libt = libtorrent;
using namespace Net;
PortForwarder::PortForwarder(libtorrent::session *provider, QObject *parent)
: QObject(parent)
, m_active(false)
, m_provider(provider)
{
configure();
connect(Preferences::instance(), SIGNAL(changed()), SLOT(configure()));
}
PortForwarder::~PortForwarder()
{
stop();
}
void PortForwarder::initInstance(libtorrent::session *const provider)
{
if (!m_instance)
m_instance = new PortForwarder(provider);
}
void PortForwarder::freeInstance()
{
if (m_instance) {
delete m_instance;
m_instance = 0;
}
}
PortForwarder *PortForwarder::instance()
{
return m_instance;
}
void PortForwarder::addPort(qint16 port)
{
if (!m_mappedPorts.contains(port)) {
m_mappedPorts.insert(port, 0);
if (m_active)
m_mappedPorts[port] = m_provider->add_port_mapping(libt::session::tcp, port, port);
}
}
void PortForwarder::deletePort(qint16 port)
{
if (m_mappedPorts.contains(port)) {
if (m_active)
m_provider->delete_port_mapping(m_mappedPorts[port]);
m_mappedPorts.remove(port);
}
}
void PortForwarder::configure()
{
bool enable = Preferences::instance()->isUPnPEnabled();
if (m_active != enable) {
if (enable)
start();
else
stop();
}
}
void PortForwarder::start()
{
qDebug("Enabling UPnP / NAT-PMP");
m_provider->start_upnp();
m_provider->start_natpmp();
foreach (qint16 port, m_mappedPorts.keys())
m_mappedPorts[port] = m_provider->add_port_mapping(libt::session::tcp, port, port);
m_active = true;
Logger::instance()->addMessage(tr("UPnP / NAT-PMP support [ON]"), Log::INFO);
}
void PortForwarder::stop()
{
qDebug("Disabling UPnP / NAT-PMP");
m_provider->stop_upnp();
m_provider->stop_natpmp();
m_active = false;
Logger::instance()->addMessage(tr("UPnP / NAT-PMP support [OFF]"), Log::INFO);
}
PortForwarder *PortForwarder::m_instance = 0;

View File

@@ -0,0 +1,73 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#ifndef NET_PORTFORWARDER_H
#define NET_PORTFORWARDER_H
#include <QObject>
#include <QHash>
namespace libtorrent
{
class session;
}
namespace Net
{
class PortForwarder : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(PortForwarder)
public:
static void initInstance(libtorrent::session *const provider);
static void freeInstance();
static PortForwarder *instance();
void addPort(qint16 port);
void deletePort(qint16 port);
private slots:
void configure();
private:
explicit PortForwarder(libtorrent::session *const provider, QObject *parent = 0);
~PortForwarder();
void start();
void stop();
bool m_active;
libtorrent::session *m_provider;
QHash<qint16, int> m_mappedPorts;
static PortForwarder *m_instance;
};
}
#endif // NET_PORTFORWARDER_H

View File

@@ -0,0 +1,520 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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 <QDebug>
#include <QVariant>
#include <QHash>
#include <QHostAddress>
#include <QDateTime>
#include <QFile>
#include "core/types.h"
#include "geoipdatabase.h"
namespace
{
const quint32 __ENDIAN_TEST__ = 0x00000001;
const bool __IS_LITTLE_ENDIAN__ = (reinterpret_cast<const uchar *>(&__ENDIAN_TEST__)[0] == 0x01);
const int MAX_FILE_SIZE = 10485760; // 10MB
const char DB_TYPE[] = "GeoLite2-Country";
const quint32 MAX_METADATA_SIZE = 131072; // 128KB
const char METADATA_BEGIN_MARK[] = "\xab\xcd\xefMaxMind.com";
const char DATA_SECTION_SEPARATOR[16] = { 0 };
enum class DataType
{
Unknown = 0,
Pointer = 1,
String = 2,
Double = 3,
Bytes = 4,
Integer16 = 5,
Integer32 = 6,
Map = 7,
SignedInteger32 = 8,
Integer64 = 9,
Integer128 = 10,
Array = 11,
DataCacheContainer = 12,
EndMarker = 13,
Boolean = 14,
Float = 15
};
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
Q_IPV6ADDR createMappedAddress(quint32 ip4);
#endif
}
struct DataFieldDescriptor
{
DataType fieldType;
union
{
quint32 fieldSize;
quint32 offset; // Pointer
};
};
GeoIPDatabase::GeoIPDatabase(quint32 size)
: m_ipVersion(0)
, m_recordSize(0)
, m_nodeCount(0)
, m_nodeSize(0)
, m_indexSize(0)
, m_recordBytes(0)
, m_size(size)
, m_data(new uchar[size])
{
}
GeoIPDatabase *GeoIPDatabase::load(const QString &filename, QString &error)
{
GeoIPDatabase *db = 0;
QFile file(filename);
if (file.size() > MAX_FILE_SIZE) {
error = tr("Unsupported database file size.");
return 0;
}
if (!file.open(QFile::ReadOnly)) {
error = file.errorString();
return 0;
}
db = new GeoIPDatabase(file.size());
if (file.read((char *)db->m_data, db->m_size) != db->m_size) {
error = file.errorString();
delete db;
return 0;
}
if (!db->parseMetadata(db->readMetadata(), error) || !db->loadDB(error)) {
delete db;
return 0;
}
return db;
}
GeoIPDatabase *GeoIPDatabase::load(const QByteArray &data, QString &error)
{
GeoIPDatabase *db = 0;
if (data.size() > MAX_FILE_SIZE) {
error = tr("Unsupported database file size.");
return 0;
}
db = new GeoIPDatabase(data.size());
memcpy((char *)db->m_data, data.constData(), db->m_size);
if (!db->parseMetadata(db->readMetadata(), error) || !db->loadDB(error)) {
delete db;
return 0;
}
return db;
}
GeoIPDatabase::~GeoIPDatabase()
{
delete [] m_data;
}
QString GeoIPDatabase::type() const
{
return DB_TYPE;
}
quint16 GeoIPDatabase::ipVersion() const
{
return m_ipVersion;
}
QDateTime GeoIPDatabase::buildEpoch() const
{
return m_buildEpoch;
}
QString GeoIPDatabase::lookup(const QHostAddress &hostAddr) const
{
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
Q_IPV6ADDR addr = hostAddr.protocol() == QAbstractSocket::IPv4Protocol
? createMappedAddress(hostAddr.toIPv4Address())
: hostAddr.toIPv6Address();
#else
Q_IPV6ADDR addr = hostAddr.toIPv6Address();
#endif
const uchar *ptr = m_data;
for (int i = 0; i < 16; ++i) {
for (int j = 0; j < 8; ++j) {
bool right = static_cast<bool>((addr[i] >> (7 - j)) & 1);
// Interpret the left/right record as number
if (right)
ptr += m_recordBytes;
quint32 id = 0;
uchar *idPtr = reinterpret_cast<uchar *>(&id);
memcpy(&idPtr[4 - m_recordBytes], ptr, m_recordBytes);
fromBigEndian(idPtr, 4);
if (id == m_nodeCount) {
return QString();
}
else if (id > m_nodeCount) {
QString country = m_countries.value(id);
if (country.isEmpty()) {
const quint32 offset = id - m_nodeCount - sizeof(DATA_SECTION_SEPARATOR);
quint32 tmp = offset + m_indexSize + sizeof(DATA_SECTION_SEPARATOR);
QVariant val = readDataField(tmp);
if (val.userType() == QMetaType::QVariantHash) {
country = val.toHash()["country"].toHash()["iso_code"].toString();
m_countries[id] = country;
}
}
return country;
}
else {
ptr = m_data + (id * m_nodeSize);
}
}
}
return QString();
}
#define CHECK_METADATA_REQ(key, type) \
if (!metadata.contains(#key)) { \
error = errMsgNotFound.arg(#key); \
return false; \
} \
else if (metadata.value(#key).userType() != QMetaType::type) { \
error = errMsgInvalid.arg(#key); \
return false; \
}
#define CHECK_METADATA_OPT(key, type) \
if (metadata.contains(#key)) { \
if (metadata.value(#key).userType() != QMetaType::type) { \
error = errMsgInvalid.arg(#key); \
return false; \
} \
}
bool GeoIPDatabase::parseMetadata(const QVariantHash &metadata, QString &error)
{
const QString errMsgNotFound = tr("Metadata error: '%1' entry not found.");
const QString errMsgInvalid = tr("Metadata error: '%1' entry has invalid type.");
qDebug() << "Parsing MaxMindDB metadata...";
CHECK_METADATA_REQ(binary_format_major_version, UShort);
CHECK_METADATA_REQ(binary_format_minor_version, UShort);
uint versionMajor = metadata.value("binary_format_major_version").toUInt();
uint versionMinor = metadata.value("binary_format_minor_version").toUInt();
if (versionMajor != 2) {
error = tr("Unsupported database version: %1.%2").arg(versionMajor).arg(versionMinor);
return false;
}
CHECK_METADATA_REQ(ip_version, UShort);
m_ipVersion = metadata.value("ip_version").value<quint16>();
if (m_ipVersion != 6) {
error = tr("Unsupported IP version: %1").arg(m_ipVersion);
return false;
}
CHECK_METADATA_REQ(record_size, UShort);
m_recordSize = metadata.value("record_size").value<quint16>();
if (m_recordSize != 24) {
error = tr("Unsupported record size: %1").arg(m_recordSize);
return false;
}
m_nodeSize = m_recordSize / 4;
m_recordBytes = m_nodeSize / 2;
CHECK_METADATA_REQ(node_count, UInt);
m_nodeCount = metadata.value("node_count").value<quint32>();
m_indexSize = m_nodeCount * m_nodeSize;
CHECK_METADATA_REQ(database_type, QString);
QString dbType = metadata.value("database_type").toString();
if (dbType != DB_TYPE) {
error = tr("Invalid database type: %1").arg(dbType);
return false;
}
CHECK_METADATA_REQ(build_epoch, ULongLong);
m_buildEpoch = QDateTime::fromTime_t(metadata.value("build_epoch").toULongLong());
CHECK_METADATA_OPT(languages, QVariantList);
CHECK_METADATA_OPT(description, QVariantHash);
return true;
}
bool GeoIPDatabase::loadDB(QString &error) const
{
qDebug() << "Parsing MaxMindDB index tree...";
const int nodeSize = m_recordSize / 4; // in bytes
const int indexSize = m_nodeCount * nodeSize;
if ((m_size < (indexSize + sizeof(DATA_SECTION_SEPARATOR)))
|| (memcmp(m_data + indexSize, DATA_SECTION_SEPARATOR, sizeof(DATA_SECTION_SEPARATOR)) != 0)) {
error = tr("Database corrupted: no data section found.");
return false;
}
return true;
}
QVariantHash GeoIPDatabase::readMetadata() const
{
const char *ptr = reinterpret_cast<const char *>(m_data);
quint32 size = m_size;
if (m_size > MAX_METADATA_SIZE) {
ptr += m_size - MAX_METADATA_SIZE;
size = MAX_METADATA_SIZE;
}
const QByteArray data = QByteArray::fromRawData(ptr, size);
int index = data.lastIndexOf(METADATA_BEGIN_MARK);
if (index >= 0) {
if (m_size > MAX_METADATA_SIZE)
index += (m_size - MAX_METADATA_SIZE); // from begin of all data
quint32 offset = static_cast<quint32>(index + strlen(METADATA_BEGIN_MARK));
QVariant metadata = readDataField(offset);
if (metadata.userType() == QMetaType::QVariantHash)
return metadata.toHash();
}
return QVariantHash();
}
QVariant GeoIPDatabase::readDataField(quint32 &offset) const
{
DataFieldDescriptor descr;
if (!readDataFieldDescriptor(offset, descr))
return QVariant();
quint32 locOffset = offset;
bool usePointer = false;
if (descr.fieldType == DataType::Pointer) {
usePointer = true;
// convert offset from data section to global
locOffset = descr.offset + (m_nodeCount * m_recordSize / 4) + sizeof(DATA_SECTION_SEPARATOR);
if (!readDataFieldDescriptor(locOffset, descr))
return QVariant();
}
QVariant fieldValue;
switch (descr.fieldType) {
case DataType::Pointer:
qDebug() << "* Illegal Pointer using";
break;
case DataType::String:
fieldValue = QString::fromUtf8(reinterpret_cast<const char *>(m_data + locOffset), descr.fieldSize);
locOffset += descr.fieldSize;
break;
case DataType::Double:
if (descr.fieldSize == 8)
fieldValue = readPlainValue<double>(locOffset, descr.fieldSize);
else
qDebug() << "* Invalid field size for type: Double";
break;
case DataType::Bytes:
fieldValue = QByteArray(reinterpret_cast<const char *>(m_data + locOffset), descr.fieldSize);
locOffset += descr.fieldSize;
break;
case DataType::Integer16:
fieldValue = readPlainValue<quint16>(locOffset, descr.fieldSize);
break;
case DataType::Integer32:
fieldValue = readPlainValue<quint32>(locOffset, descr.fieldSize);
break;
case DataType::Map:
fieldValue = readMapValue(locOffset, descr.fieldSize);
break;
case DataType::SignedInteger32:
fieldValue = readPlainValue<qint32>(locOffset, descr.fieldSize);
break;
case DataType::Integer64:
fieldValue = readPlainValue<quint64>(locOffset, descr.fieldSize);
break;
case DataType::Integer128:
qDebug() << "* Unsupported data type: Integer128";
break;
case DataType::Array:
fieldValue = readArrayValue(locOffset, descr.fieldSize);
break;
case DataType::DataCacheContainer:
qDebug() << "* Unsupported data type: DataCacheContainer";
break;
case DataType::EndMarker:
qDebug() << "* Unsupported data type: EndMarker";
break;
case DataType::Boolean:
fieldValue = QVariant::fromValue(static_cast<bool>(descr.fieldSize));
break;
case DataType::Float:
if (descr.fieldSize == 4)
fieldValue = readPlainValue<float>(locOffset, descr.fieldSize);
else
qDebug() << "* Invalid field size for type: Float";
break;
default:
qDebug() << "* Unsupported data type: Unknown";
}
if (!usePointer)
offset = locOffset;
return fieldValue;
}
bool GeoIPDatabase::readDataFieldDescriptor(quint32 &offset, DataFieldDescriptor &out) const
{
const uchar *dataPtr = m_data + offset;
int availSize = m_size - offset;
if (availSize < 1) return false;
out.fieldType = static_cast<DataType>((dataPtr[0] & 0xE0) >> 5);
if (out.fieldType == DataType::Pointer) {
int size = ((dataPtr[0] & 0x18) >> 3);
if (availSize < (size + 2)) return false;
if (size == 0)
out.offset = ((dataPtr[0] & 0x07) << 8) + dataPtr[1];
else if (size == 1)
out.offset = ((dataPtr[0] & 0x07) << 16) + (dataPtr[1] << 8) + dataPtr[2] + 2048;
else if (size == 2)
out.offset = ((dataPtr[0] & 0x07) << 24) + (dataPtr[1] << 16) + (dataPtr[2] << 8) + dataPtr[3] + 526336;
else if (size == 3)
out.offset = (dataPtr[1] << 24) + (dataPtr[2] << 16) + (dataPtr[3] << 8) + dataPtr[4];
offset += size + 2;
return true;
}
out.fieldSize = dataPtr[0] & 0x1F;
if (out.fieldSize <= 28) {
if (out.fieldType == DataType::Unknown) {
out.fieldType = static_cast<DataType>(dataPtr[1] + 7);
if ((out.fieldType <= DataType::Map) || (out.fieldType > DataType::Float) || (availSize < 3))
return false;
offset += 2;
}
else {
offset += 1;
}
}
else if (out.fieldSize == 29) {
if (availSize < 2) return false;
out.fieldSize = dataPtr[1] + 29;
offset += 2;
}
else if (out.fieldSize == 30) {
if (availSize < 3) return false;
out.fieldSize = (dataPtr[1] << 8) + dataPtr[2] + 285;
offset += 3;
}
else if (out.fieldSize == 31) {
if (availSize < 4) return false;
out.fieldSize = (dataPtr[1] << 16) + (dataPtr[2] << 8) + dataPtr[3] + 65821;
offset += 4;
}
return true;
}
void GeoIPDatabase::fromBigEndian(uchar *buf, quint32 len) const
{
if (__IS_LITTLE_ENDIAN__)
std::reverse(buf, buf + len);
}
QVariant GeoIPDatabase::readMapValue(quint32 &offset, quint32 count) const
{
QVariantHash map;
for (quint32 i = 0; i < count; ++i) {
QVariant field = readDataField(offset);
if (field.userType() != QMetaType::QString)
return QVariant();
QString key = field.toString();
field = readDataField(offset);
if (field.userType() == QVariant::Invalid)
return QVariant();
map[key] = field;
}
return map;
}
QVariant GeoIPDatabase::readArrayValue(quint32 &offset, quint32 count) const
{
QVariantList array;
for (quint32 i = 0; i < count; ++i) {
QVariant field = readDataField(offset);
if (field.userType() == QVariant::Invalid)
return QVariant();
array.append(field);
}
return array;
}
namespace
{
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
Q_IPV6ADDR createMappedAddress(quint32 ip4)
{
Q_IPV6ADDR ip6;
memset(&ip6, 0, sizeof(ip6));
int i;
for (i = 15; ip4 != 0; i--) {
ip6[i] = ip4 & 0xFF;
ip4 >>= 8;
}
ip6[11] = 0xFF;
ip6[10] = 0xFF;
return ip6;
}
#endif
}

View File

@@ -0,0 +1,102 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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 GEOIPDATABASE_H
#define GEOIPDATABASE_H
#include <QtGlobal>
#include <QCoreApplication>
class QHostAddress;
class QString;
class QByteArray;
class QDateTime;
struct DataFieldDescriptor;
class GeoIPDatabase
{
Q_DECLARE_TR_FUNCTIONS(GeoIPDatabase)
public:
static GeoIPDatabase *load(const QString &filename, QString &error);
static GeoIPDatabase *load(const QByteArray &data, QString &error);
~GeoIPDatabase();
QString type() const;
quint16 ipVersion() const;
QDateTime buildEpoch() const;
QString lookup(const QHostAddress &hostAddr) const;
private:
GeoIPDatabase(quint32 size);
bool parseMetadata(const QVariantHash &metadata, QString &error);
bool loadDB(QString &error) const;
QVariantHash readMetadata() const;
QVariant readDataField(quint32 &offset) const;
bool readDataFieldDescriptor(quint32 &offset, DataFieldDescriptor &out) const;
void fromBigEndian(uchar *buf, quint32 len) const;
QVariant readMapValue(quint32 &offset, quint32 count) const;
QVariant readArrayValue(quint32 &offset, quint32 count) const;
template<typename T>
QVariant readPlainValue(quint32 &offset, quint8 len) const
{
T value = 0;
const uchar *const data = m_data + offset;
const quint32 availSize = m_size - offset;
if ((len > 0) && (len <= sizeof(T) && (availSize >= len))) {
// copy input data to last 'len' bytes of 'value'
uchar *dst = reinterpret_cast<uchar *>(&value) + (sizeof(T) - len);
memcpy(dst, data, len);
fromBigEndian(reinterpret_cast<uchar *>(&value), sizeof(T));
offset += len;
}
return QVariant::fromValue(value);
}
// Metadata
quint16 m_ipVersion;
quint16 m_recordSize;
quint32 m_nodeCount;
int m_nodeSize;
int m_indexSize;
int m_recordBytes;
QDateTime m_buildEpoch;
// Search data
mutable QHash<quint32, QString> m_countries;
quint32 m_size;
const uchar *m_data;
};
#endif // GEOIPDATABASE_H

View File

@@ -1,5 +1,5 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
@@ -28,74 +28,63 @@
* Contact : chris@qbittorrent.org
*/
#ifndef REVERSERESOLUTION_H
#define REVERSERESOLUTION_H
#include <QList>
#include <QCache>
#include <QDebug>
#include <QHostInfo>
#include "misc.h"
#include <QString>
#include <boost/version.hpp>
#include <boost/asio/ip/tcp.hpp>
#include "reverseresolution.h"
const int CACHE_SIZE = 500;
class ReverseResolution: public QObject {
Q_OBJECT
Q_DISABLE_COPY(ReverseResolution)
using namespace Net;
public:
explicit ReverseResolution(QObject* parent): QObject(parent) {
static inline bool isUsefulHostName(const QString &hostname, const QString &ip)
{
return (!hostname.isEmpty() && hostname != ip);
}
ReverseResolution::ReverseResolution(QObject *parent)
: QObject(parent)
{
m_cache.setMaxCost(CACHE_SIZE);
}
}
~ReverseResolution() {
ReverseResolution::~ReverseResolution()
{
qDebug("Deleting host name resolver...");
}
}
void resolve(const QString &ip) {
void ReverseResolution::resolve(const QString &ip)
{
if (m_cache.contains(ip)) {
const QString& hostname = *m_cache.object(ip);
qDebug() << "Resolved host name using cache: " << ip << " -> " << hostname;
if (isUsefulHostName(hostname, ip))
emit ip_resolved(ip, hostname);
return;
const QString &hostname = *m_cache.object(ip);
qDebug() << "Resolved host name using cache: " << ip << " -> " << hostname;
if (isUsefulHostName(hostname, ip))
emit ipResolved(ip, hostname);
}
// Actually resolve the ip
m_lookups.insert(QHostInfo::lookupHost(ip, this, SLOT(hostResolved(QHostInfo))), ip);
}
else {
// Actually resolve the ip
m_lookups.insert(QHostInfo::lookupHost(ip, this, SLOT(hostResolved(QHostInfo))), ip);
}
}
signals:
void ip_resolved(const QString &ip, const QString &hostname);
private slots:
void hostResolved(const QHostInfo& host) {
const QString& ip = m_lookups.take(host.lookupId());
void ReverseResolution::hostResolved(const QHostInfo &host)
{
const QString &ip = m_lookups.take(host.lookupId());
Q_ASSERT(!ip.isNull());
if (host.error() != QHostInfo::NoError) {
qDebug() << "DNS Reverse resolution error: " << host.errorString();
return;
qDebug() << "DNS Reverse resolution error: " << host.errorString();
return;
}
const QString& hostname = host.hostName();
const QString &hostname = host.hostName();
qDebug() << Q_FUNC_INFO << ip << QString("->") << hostname;
m_cache.insert(ip, new QString(hostname));
if (isUsefulHostName(hostname, ip))
emit ip_resolved(ip, hostname);
}
private:
static inline bool isUsefulHostName(const QString& hostname, const QString& ip) {
return (!hostname.isEmpty() && hostname != ip);
}
QHash<int /* LookupID */, QString /* IP */> m_lookups;
QCache<QString /* IP */, QString /* HostName */> m_cache;
};
#endif // REVERSERESOLUTION_H
emit ipResolved(ip, hostname);
}

View File

@@ -0,0 +1,67 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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.
*
* Contact : chris@qbittorrent.org
*/
#ifndef NET_REVERSERESOLUTION_H
#define NET_REVERSERESOLUTION_H
#include <QCache>
#include <QObject>
QT_BEGIN_NAMESPACE
class QHostInfo;
class QString;
QT_END_NAMESPACE
namespace Net
{
class ReverseResolution : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(ReverseResolution)
public:
explicit ReverseResolution(QObject *parent = 0);
~ReverseResolution();
void resolve(const QString &ip);
signals:
void ipResolved(const QString &ip, const QString &hostname);
private slots:
void hostResolved(const QHostInfo &host);
private:
QHash<int /* LookupID */, QString /* IP */> m_lookups;
QCache<QString /* IP */, QString /* HostName */> m_cache;
};
}
#endif // NET_REVERSERESOLUTION_H

502
src/core/net/smtp.cpp Normal file
View File

@@ -0,0 +1,502 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2011 Christophe Dumez
*
* 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.
*
* Contact : chris@qbittorrent.org
*/
/*
* This code is based on QxtSmtp from libqxt (http://libqxt.org)
*/
#include "smtp.h"
#include "core/preferences.h"
#include "core/logger.h"
#include <QTextStream>
#ifndef QT_NO_OPENSSL
#include <QSslSocket>
#else
#include <QTcpSocket>
#endif
#include <QTextCodec>
#include <QDebug>
#include <QHostAddress>
#include <QHostInfo>
#include <QNetworkInterface>
#include <QCryptographicHash>
#include <QStringList>
namespace
{
const short DEFAULT_PORT = 25;
const short DEFAULT_PORT_SSL = 465;
QByteArray hmacMD5(QByteArray key, const QByteArray &msg)
{
const int blockSize = 64; // HMAC-MD5 block size
if (key.length() > blockSize) { // if key is longer than block size (64), reduce key length with MD5 compression
key = QCryptographicHash::hash(key, QCryptographicHash::Md5);
}
QByteArray innerPadding(blockSize, char(0x36)); // initialize inner padding with char "6"
QByteArray outerPadding(blockSize, char(0x5c)); // initialize outer padding with char "\"
// ascii characters 0x36 ("6") and 0x5c ("\") are selected because they have large
// Hamming distance (http://en.wikipedia.org/wiki/Hamming_distance)
for (int i = 0; i < key.length(); i++) {
innerPadding[i] = innerPadding[i] ^ key.at(i); // XOR operation between every byte in key and innerpadding, of key length
outerPadding[i] = outerPadding[i] ^ key.at(i); // XOR operation between every byte in key and outerpadding, of key length
}
// result = hash ( outerPadding CONCAT hash ( innerPadding CONCAT baseString ) ).toBase64
QByteArray total = outerPadding;
QByteArray part = innerPadding;
part.append(msg);
total.append(QCryptographicHash::hash(part, QCryptographicHash::Md5));
return QCryptographicHash::hash(total, QCryptographicHash::Md5);
}
QByteArray determineFQDN()
{
QString hostname = QHostInfo::localHostName();
if (hostname.isEmpty())
hostname = "localhost";
return hostname.toLocal8Bit();
}
} // namespace
using namespace Net;
Smtp::Smtp(QObject *parent)
: QObject(parent)
, m_state(Init)
, m_useSsl(false)
{
#ifndef QT_NO_OPENSSL
m_socket = new QSslSocket(this);
#else
m_socket = new QTcpSocket(this);
#endif
connect(m_socket, SIGNAL(readyRead()), SLOT(readyRead()));
connect(m_socket, SIGNAL(disconnected()), SLOT(deleteLater()));
// Test hmacMD5 function (http://www.faqs.org/rfcs/rfc2202.html)
Q_ASSERT(hmacMD5("Jefe", "what do ya want for nothing?").toHex()
== "750c783e6ab0b503eaa86e310a5db738");
Q_ASSERT(hmacMD5(QByteArray::fromHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), "Hi There").toHex()
== "9294727a3638bb1c13f48ef8158bfc9d");
}
Smtp::~Smtp()
{
qDebug() << Q_FUNC_INFO;
}
void Smtp::sendMail(const QString &from, const QString &to, const QString &subject, const QString &body)
{
const Preferences* const pref = Preferences::instance();
QTextCodec* latin1 = QTextCodec::codecForName("latin1");
m_message = "";
m_message += encodeMimeHeader("Date", QDateTime::currentDateTime().toUTC().toString("ddd, d MMM yyyy hh:mm:ss UT"), latin1);
m_message += encodeMimeHeader("From", from, latin1);
m_message += encodeMimeHeader("Subject", subject, latin1);
m_message += encodeMimeHeader("To", to, latin1);
m_message += "MIME-Version: 1.0\r\n";
m_message += "Content-Type: text/plain; charset=UTF-8\r\n";
m_message += "Content-Transfer-Encoding: base64\r\n";
m_message += "\r\n";
// Encode the body in base64
QString crlf_body = body;
QByteArray b = crlf_body.replace("\n","\r\n").toUtf8().toBase64();
int ct = b.length();
for (int i = 0; i < ct; i += 78)
m_message += b.mid(i, 78);
m_from = from;
m_rcpt = to;
// Authentication
if (pref->getMailNotificationSMTPAuth()) {
m_username = pref->getMailNotificationSMTPUsername();
m_password = pref->getMailNotificationSMTPPassword();
}
// Connect to SMTP server
#ifndef QT_NO_OPENSSL
if (pref->getMailNotificationSMTPSSL()) {
m_socket->connectToHostEncrypted(pref->getMailNotificationSMTP(), DEFAULT_PORT_SSL);
m_useSsl = true;
}
else {
#endif
m_socket->connectToHost(pref->getMailNotificationSMTP(), DEFAULT_PORT);
m_useSsl = false;
#ifndef QT_NO_OPENSSL
}
#endif
}
void Smtp::readyRead()
{
qDebug() << Q_FUNC_INFO;
// SMTP is line-oriented
m_buffer += m_socket->readAll();
while (true) {
int pos = m_buffer.indexOf("\r\n");
if (pos < 0) return; // Loop exit condition
QByteArray line = m_buffer.left(pos);
m_buffer = m_buffer.mid(pos + 2);
qDebug() << "Response line:" << line;
// Extract response code
QByteArray code = line.left(3);
switch (m_state) {
case Init: {
if (code[0] == '2') {
// The server may send a multiline greeting/INIT/220 response.
// We wait until it finishes.
if (line[3] != ' ')
break;
// Connection was successful
ehlo();
}
else {
logError("Connection failed, unrecognized reply: "+line);
m_state = Close;
}
break;
}
case EhloSent:
case HeloSent:
case EhloGreetReceived:
parseEhloResponse(code, line[3] != ' ', line.mid(4));
break;
#ifndef QT_NO_OPENSSL
case StartTLSSent:
if (code == "220") {
m_socket->startClientEncryption();
ehlo();
}
else {
authenticate();
}
break;
#endif
case AuthRequestSent:
case AuthUsernameSent:
if (m_authType == AuthPlain) authPlain();
else if (m_authType == AuthLogin) authLogin();
else authCramMD5(line.mid(4));
break;
case AuthSent:
case Authenticated:
if (code[0] == '2') {
qDebug() << "Sending <mail from>...";
m_socket->write("mail from:<" + m_from.toLatin1() + ">\r\n");
m_socket->flush();
m_state = Rcpt;
}
else {
// Authentication failed!
logError("Authentication failed, msg: "+line);
m_state = Close;
}
break;
case Rcpt:
if (code[0] == '2') {
m_socket->write("rcpt to:<" + m_rcpt.toLatin1() + ">\r\n");
m_socket->flush();
m_state = Data;
}
else {
logError("<mail from> was rejected by server, msg: "+line);
m_state = Close;
}
break;
case Data:
if (code[0] == '2') {
m_socket->write("data\r\n");
m_socket->flush();
m_state = Body;
}
else {
logError("<Rcpt to> was rejected by server, msg: "+line);
m_state = Close;
}
break;
case Body:
if (code[0] == '3') {
m_socket->write(m_message + "\r\n.\r\n");
m_socket->flush();
m_state = Quit;
}
else {
logError("<data> was rejected by server, msg: "+line);
m_state = Close;
}
break;
case Quit:
if (code[0] == '2') {
m_socket->write("QUIT\r\n");
m_socket->flush();
// here, we just close.
m_state = Close;
}
else {
logError("Message was rejected by the server, error: "+line);
m_state = Close;
}
break;
default:
qDebug() << "Disconnecting from host";
m_socket->disconnectFromHost();
return;
}
}
}
QByteArray Smtp::encodeMimeHeader(const QString &key, const QString &value, QTextCodec *latin1, const QByteArray &prefix)
{
QByteArray rv = "";
QByteArray line = key.toLatin1() + ": ";
if (!prefix.isEmpty()) line += prefix;
if (!value.contains("=?") && latin1->canEncode(value)) {
bool firstWord = true;
foreach (const QByteArray& word, value.toLatin1().split(' ')) {
if (line.size() > 78) {
rv = rv + line + "\r\n";
line.clear();
}
if (firstWord)
line += word;
else
line += " " + word;
firstWord = false;
}
}
else {
// The text cannot be losslessly encoded as Latin-1. Therefore, we
// must use base64 encoding.
QByteArray utf8 = value.toUtf8();
// Use base64 encoding
QByteArray base64 = utf8.toBase64();
int ct = base64.length();
line += "=?utf-8?b?";
for (int i = 0; i < ct; i += 4) {
/*if (line.length() > 72) {
rv += line + "?\n\r";
line = " =?utf-8?b?";
}*/
line = line + base64.mid(i, 4);
}
line += "?="; // end encoded-word atom
}
return rv + line + "\r\n";
}
void Smtp::ehlo()
{
QByteArray address = determineFQDN();
m_socket->write("ehlo " + address + "\r\n");
m_socket->flush();
m_state = EhloSent;
}
void Smtp::helo()
{
QByteArray address = determineFQDN();
m_socket->write("helo " + address + "\r\n");
m_socket->flush();
m_state = HeloSent;
}
void Smtp::parseEhloResponse(const QByteArray &code, bool continued, const QString &line)
{
if (code != "250") {
// Error
if (m_state == EhloSent) {
// try to send HELO instead of EHLO
qDebug() << "EHLO failed, trying HELO instead...";
helo();
}
else {
// Both EHLO and HELO failed, chances are this is NOT
// a SMTP server
logError("Both EHLO and HELO failed, msg: "+line);
m_state = Close;
}
return;
}
if (m_state != EhloGreetReceived) {
if (!continued) {
// greeting only, no extensions
qDebug() << "No extension";
m_state = EhloDone;
}
else {
// greeting followed by extensions
m_state = EhloGreetReceived;
qDebug () << "EHLO greet received";
return;
}
}
else {
qDebug() << Q_FUNC_INFO << "Supported extension: " << line.section(' ', 0, 0).toUpper()
<< line.section(' ', 1);
m_extensions[line.section(' ', 0, 0).toUpper()] = line.section(' ', 1);
if (!continued)
m_state = EhloDone;
}
if (m_state != EhloDone) return;
if (m_extensions.contains("STARTTLS") && m_useSsl) {
qDebug() << "STARTTLS";
startTLS();
}
else {
authenticate();
}
}
void Smtp::authenticate()
{
qDebug() << Q_FUNC_INFO;
if (!m_extensions.contains("AUTH") ||
m_username.isEmpty() || m_password.isEmpty()) {
// Skip authentication
qDebug() << "Skipping authentication...";
m_state = Authenticated;
// At this point the server will not send any response
// So fill the buffer with a fake one to pass the tests
// in readyRead()
m_buffer.push_front("250 QBT FAKE RESPONSE\r\n");
return;
}
// AUTH extension is supported, check which
// authentication modes are supported by
// the server
QStringList auth = m_extensions["AUTH"].toUpper().split(' ', QString::SkipEmptyParts);
if (auth.contains("CRAM-MD5")) {
qDebug() << "Using CRAM-MD5 authentication...";
authCramMD5();
}
else if (auth.contains("PLAIN")) {
qDebug() << "Using PLAIN authentication...";
authPlain();
}
else if (auth.contains("LOGIN")) {
qDebug() << "Using LOGIN authentication...";
authLogin();
}
else {
// Skip authentication
logError("The SMTP server does not seem to support any of the authentications modes "
"we support [CRAM-MD5|PLAIN|LOGIN], skipping authentication, "
"knowing it is likely to fail... Server Auth Modes: "+auth.join("|"));
m_state = Authenticated;
// At this point the server will not send any response
// So fill the buffer with a fake one to pass the tests
// in readyRead()
m_buffer.push_front("250 QBT FAKE RESPONSE\r\n");
}
}
void Smtp::startTLS()
{
qDebug() << Q_FUNC_INFO;
#ifndef QT_NO_OPENSSL
m_socket->write("starttls\r\n");
m_socket->flush();
m_state = StartTLSSent;
#else
authenticate();
#endif
}
void Smtp::authCramMD5(const QByteArray& challenge)
{
if (m_state != AuthRequestSent) {
m_socket->write("auth cram-md5\r\n");
m_socket->flush();
m_authType = AuthCramMD5;
m_state = AuthRequestSent;
}
else {
QByteArray response = m_username.toLatin1() + ' '
+ hmacMD5(m_password.toLatin1(), QByteArray::fromBase64(challenge)).toHex();
m_socket->write(response.toBase64() + "\r\n");
m_socket->flush();
m_state = AuthSent;
}
}
void Smtp::authPlain()
{
if (m_state != AuthRequestSent) {
m_authType = AuthPlain;
// Prepare Auth string
QByteArray auth;
auth += '\0';
auth += m_username.toLatin1();
qDebug() << "username: " << m_username.toLatin1();
auth += '\0';
auth += m_password.toLatin1();
qDebug() << "password: " << m_password.toLatin1();
// Send it
m_socket->write("auth plain "+ auth.toBase64() + "\r\n");
m_socket->flush();
m_state = AuthSent;
}
}
void Smtp::authLogin()
{
if ((m_state != AuthRequestSent) && (m_state != AuthUsernameSent)) {
m_socket->write("auth login\r\n");
m_socket->flush();
m_authType = AuthLogin;
m_state = AuthRequestSent;
}
else if (m_state == AuthRequestSent) {
m_socket->write(m_username.toLatin1().toBase64() + "\r\n");
m_socket->flush();
m_state = AuthUsernameSent;
}
else {
m_socket->write(m_password.toLatin1().toBase64() + "\r\n");
m_socket->flush();
m_state = AuthSent;
}
}
void Smtp::logError(const QString &msg)
{
qDebug() << "Email Notification Error:" << msg;
Logger::instance()->addMessage(tr("Email Notification Error:") + " " + msg, Log::CRITICAL);
}

View File

@@ -1,5 +1,5 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2011 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
@@ -50,50 +50,76 @@ class QTcpSocket;
class QTextCodec;
QT_END_NAMESPACE
class Smtp : public QObject {
Q_OBJECT
namespace Net
{
class Smtp : public QObject
{
Q_OBJECT
public:
Smtp(QObject *parent = 0);
~Smtp();
void sendMail(const QString &from, const QString &to, const QString &subject, const QString &body);
public:
Smtp(QObject *parent = 0);
~Smtp();
private slots:
void readyRead();
void sendMail(const QString &m_from, const QString &to, const QString &subject, const QString &body);
private:
QByteArray encode_mime_header(const QString& key, const QString& value, QTextCodec* latin1, const QByteArray& prefix=QByteArray());
void ehlo();
void helo();
void parseEhloResponse(const QByteArray& code, bool continued, const QString& line);
void authenticate();
void startTLS();
void authCramMD5(const QByteArray& challenge = QByteArray());
void authPlain();
void authLogin();
void logError(const QString &msg);
private slots:
void readyRead();
private:
enum states { Rcpt, EhloSent, HeloSent, EhloDone, EhloGreetReceived, AuthRequestSent, AuthSent,
AuthUsernameSent, Authenticated, StartTLSSent, Data, Init, Body, Quit, Close };
enum AuthType { AuthPlain, AuthLogin, AuthCramMD5 };
private:
enum States
{
Rcpt,
EhloSent,
HeloSent,
EhloDone,
EhloGreetReceived,
AuthRequestSent,
AuthSent,
AuthUsernameSent,
Authenticated,
StartTLSSent,
Data,
Init,
Body,
Quit,
Close
};
private:
QByteArray message;
enum AuthType
{
AuthPlain,
AuthLogin,
AuthCramMD5
};
QByteArray encodeMimeHeader(const QString &key, const QString &value, QTextCodec *latin1, const QByteArray &prefix = QByteArray());
void ehlo();
void helo();
void parseEhloResponse(const QByteArray &code, bool continued, const QString &line);
void authenticate();
void startTLS();
void authCramMD5(const QByteArray &challenge = QByteArray());
void authPlain();
void authLogin();
void logError(const QString &msg);
QByteArray m_message;
#ifndef QT_NO_OPENSSL
QSslSocket *socket;
QSslSocket *m_socket;
#else
QTcpSocket *socket;
QTcpSocket *m_socket;
#endif
QString from;
QString rcpt;
QString response;
int state;
QHash<QString, QString> extensions;
QByteArray buffer;
bool use_ssl;
AuthType authType;
QString username;
QString password;
};
QString m_from;
QString m_rcpt;
QString m_response;
int m_state;
QHash<QString, QString> m_extensions;
QByteArray m_buffer;
bool m_useSsl;
AuthType m_authType;
QString m_username;
QString m_password;
};
}
#endif

View File

@@ -32,6 +32,7 @@
#include "preferences.h"
#include "qinisettings.h"
#include "logger.h"
#include <QCryptographicHash>
#include <QPair>
@@ -50,8 +51,9 @@
#include <winreg.h>
#endif
#include "misc.h"
#include "fs_utils.h"
#include <cstdlib>
#include "core/utils/fs.h"
#include "core/utils/misc.h"
Preferences* Preferences::m_instance = 0;
@@ -61,18 +63,20 @@ Preferences::Preferences()
, dirty(false)
, lock(QReadWriteLock::Recursive)
{
qRegisterMetaTypeStreamOperators<MaxRatioAction>("MaxRatioAction");
QIniSettings *settings = new QIniSettings;
#ifndef Q_OS_MAC
QIniSettings *settings_new = new QIniSettings("qBittorrent", "qBittorrent_new");
QStringList keys = settings_new->allKeys();
bool use_new = false;
// This means that the PC closed either due to power outage
// or because the disk was full. In any case the settings weren't transfered
// in their final position. So assume that qbittorrent_new.ini/qbittorrent_new.conf
// contains the most recent settings.
if (!keys.isEmpty()) {
Logger::instance()->addMessage(tr("Detected unclean program exit. Using fallback file to restore settings."), Log::WARNING);
use_new = true;
dirty = true;
}
@@ -100,7 +104,9 @@ Preferences::Preferences()
//Ensures sync to disk before we attempt to manipulate the files from save().
delete settings;
#ifndef Q_OS_MAC
QString new_path = settings_new->fileName();
delete settings_new;
Utils::Fs::forceRemove(new_path);
if (use_new)
save();
@@ -116,15 +122,18 @@ Preferences::~Preferences()
save();
}
Preferences * Preferences::instance()
Preferences *Preferences::instance()
{
if (!m_instance)
m_instance = new Preferences;
return m_instance;
}
void Preferences::drop()
void Preferences::initInstance()
{
if (!m_instance)
m_instance = new Preferences;
}
void Preferences::freeInstance()
{
if (m_instance) {
delete m_instance;
@@ -132,12 +141,11 @@ void Preferences::drop()
}
}
void Preferences::save()
bool Preferences::save()
{
QReadLocker locker(&lock);
QWriteLocker locker(&lock);
if (!dirty)
return;
if (!dirty) return false;
#ifndef Q_OS_MAC
// QSettings delete the file before writing it out. This can result in problems
@@ -158,22 +166,30 @@ void Preferences::save()
#ifndef Q_OS_MAC
settings->sync(); // Important to get error status
if (settings->status() == QSettings::AccessError) {
delete settings;
return;
}
QString new_path = settings->fileName();
QSettings::Status status = settings->status();
if (status != QSettings::NoError) {
if (status == QSettings::AccessError)
Logger::instance()->addMessage(tr("An access error occurred while trying to write the configuration file."), Log::CRITICAL);
else
Logger::instance()->addMessage(tr("A format error occurred while trying to write the configuration file."), Log::CRITICAL);
delete settings;
Utils::Fs::forceRemove(new_path);
return false;
}
delete settings;
QString final_path = new_path;
int index = final_path.lastIndexOf("_new", -1, Qt::CaseInsensitive);
final_path.remove(index, 4);
fsutils::forceRemove(final_path);
Utils::Fs::forceRemove(final_path);
QFile::rename(new_path, final_path);
#else
delete settings;
#endif
emit changed();
return true;
}
const QVariant Preferences::value(const QString &key, const QVariant &defaultValue) const
@@ -345,7 +361,7 @@ void Preferences::setWinStartup(bool b)
{
QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
if (b) {
const QString bin_path = "\"" + fsutils::toNativePath(qApp->applicationFilePath()) + "\"";
const QString bin_path = "\"" + Utils::Fs::toNativePath(qApp->applicationFilePath()) + "\"";
settings.setValue("qBittorrent", bin_path);
}
else {
@@ -359,13 +375,13 @@ QString Preferences::getSavePath() const
{
QString save_path = value("Preferences/Downloads/SavePath").toString();
if (!save_path.isEmpty())
return fsutils::fromNativePath(save_path);
return fsutils::QDesktopServicesDownloadLocation();
return Utils::Fs::fromNativePath(save_path);
return Utils::Fs::QDesktopServicesDownloadLocation();
}
void Preferences::setSavePath(const QString &save_path)
{
setValue("Preferences/Downloads/SavePath", fsutils::fromNativePath(save_path));
setValue("Preferences/Downloads/SavePath", Utils::Fs::fromNativePath(save_path));
}
bool Preferences::isTempPathEnabled() const
@@ -381,12 +397,12 @@ void Preferences::setTempPathEnabled(bool enabled)
QString Preferences::getTempPath() const
{
const QString temp = QDir(getSavePath()).absoluteFilePath("temp");
return fsutils::fromNativePath(value("Preferences/Downloads/TempPath", temp).toString());
return Utils::Fs::fromNativePath(value("Preferences/Downloads/TempPath", temp).toString());
}
void Preferences::setTempPath(const QString &path)
{
setValue("Preferences/Downloads/TempPath", fsutils::fromNativePath(path));
setValue("Preferences/Downloads/TempPath", Utils::Fs::fromNativePath(path));
}
bool Preferences::useIncompleteFilesExtension() const
@@ -411,12 +427,12 @@ void Preferences::setAppendTorrentLabel(bool b)
QString Preferences::lastLocationPath() const
{
return fsutils::fromNativePath(value("Preferences/Downloads/LastLocationPath").toString());
return Utils::Fs::fromNativePath(value("Preferences/Downloads/LastLocationPath").toString());
}
void Preferences::setLastLocationPath(const QString &path)
{
setValue("Preferences/Downloads/LastLocationPath", fsutils::fromNativePath(path));
setValue("Preferences/Downloads/LastLocationPath", Utils::Fs::fromNativePath(path));
}
bool Preferences::preAllocateAllFiles() const
@@ -467,7 +483,7 @@ QStringList Preferences::getScanDirs() const
QStringList newList;
foreach (const QString& s, originalList)
newList << fsutils::fromNativePath(s);
newList << Utils::Fs::fromNativePath(s);
return newList;
}
@@ -477,28 +493,38 @@ void Preferences::setScanDirs(const QStringList &dirs)
QStringList newList;
if (!dirs.isEmpty())
foreach (const QString& s, dirs)
newList << fsutils::fromNativePath(s);
newList << Utils::Fs::fromNativePath(s);
setValue("Preferences/Downloads/ScanDirs", newList);
}
QList<bool> Preferences::getDownloadInScanDirs() const
{
return misc::boolListfromStringList(value("Preferences/Downloads/DownloadInScanDirs").toStringList());
return Utils::Misc::boolListfromStringList(value("Preferences/Downloads/DownloadInScanDirs").toStringList());
}
void Preferences::setDownloadInScanDirs(const QList<bool> &list)
{
setValue("Preferences/Downloads/DownloadInScanDirs", misc::toStringList(list));
setValue("Preferences/Downloads/ScanDirsDownloadPaths", Utils::Misc::toStringList(list));
}
void Preferences::setScanDirsDownloadPaths(const QStringList &downloadpaths)
{
setValue("Preferences/Downloads/ScanDirsDownloadPaths", downloadpaths);
}
QStringList Preferences::getScanDirsDownloadPaths() const
{
return value("Preferences/Downloads/DownloadPaths").toStringList();
}
QString Preferences::getScanDirsLastPath() const
{
return fsutils::fromNativePath(value("Preferences/Downloads/ScanDirsLastPath").toString());
return Utils::Fs::fromNativePath(value("Preferences/Downloads/ScanDirsLastPath").toString());
}
void Preferences::setScanDirsLastPath(const QString &path)
{
setValue("Preferences/Downloads/ScanDirsLastPath", fsutils::fromNativePath(path));
setValue("Preferences/Downloads/ScanDirsLastPath", Utils::Fs::fromNativePath(path));
}
bool Preferences::isTorrentExportEnabled() const
@@ -508,12 +534,12 @@ bool Preferences::isTorrentExportEnabled() const
QString Preferences::getTorrentExportDir() const
{
return fsutils::fromNativePath(value("Preferences/Downloads/TorrentExportDir").toString());
return Utils::Fs::fromNativePath(value("Preferences/Downloads/TorrentExportDir").toString());
}
void Preferences::setTorrentExportDir(QString path)
{
setValue("Preferences/Downloads/TorrentExportDir", fsutils::fromNativePath(path.trimmed()));
setValue("Preferences/Downloads/TorrentExportDir", Utils::Fs::fromNativePath(path.trimmed()));
}
bool Preferences::isFinishedTorrentExportEnabled() const
@@ -523,12 +549,12 @@ bool Preferences::isFinishedTorrentExportEnabled() const
QString Preferences::getFinishedTorrentExportDir() const
{
return fsutils::fromNativePath(value("Preferences/Downloads/FinishedTorrentExportDir").toString());
return Utils::Fs::fromNativePath(value("Preferences/Downloads/FinishedTorrentExportDir").toString());
}
void Preferences::setFinishedTorrentExportDir(QString path)
{
setValue("Preferences/Downloads/FinishedTorrentExportDir", fsutils::fromNativePath(path.trimmed()));
setValue("Preferences/Downloads/FinishedTorrentExportDir", Utils::Fs::fromNativePath(path.trimmed()));
}
bool Preferences::isMailNotificationEnabled() const
@@ -819,7 +845,6 @@ void Preferences::setProxyPeerConnections(bool enabled)
setValue("Preferences/Connection/ProxyPeerConnections", enabled);
}
#if LIBTORRENT_VERSION_NUM >= 10000
bool Preferences::getForceProxy() const
{
return value("Preferences/Connection/ProxyForce", true).toBool();
@@ -829,7 +854,16 @@ void Preferences::setForceProxy(bool enabled)
{
setValue("Preferences/Connection/ProxyForce", enabled);
}
#endif
void Preferences::setProxyOnlyForTorrents(bool enabled)
{
setValue("Preferences/Connection/ProxyOnlyForTorrents", enabled);
}
bool Preferences::isProxyOnlyForTorrents() const
{
return value("Preferences/Connection/ProxyOnlyForTorrents", false).toBool();
}
// Bittorrent options
int Preferences::getMaxConnecs() const
@@ -940,6 +974,26 @@ void Preferences::setEncryptionSetting(int val)
setValue("Preferences/Bittorrent/Encryption", val);
}
bool Preferences::isAddTrackersEnabled() const
{
return value("Preferences/Bittorrent/AddTrackers", false).toBool();
}
void Preferences::setAddTrackersEnabled(bool enabled)
{
setValue("Preferences/Bittorrent/AddTrackers", enabled);
}
QString Preferences::getTrackersList() const
{
return value("Preferences/Bittorrent/TrackersList").toString();
}
void Preferences::setTrackersList(const QString &val)
{
setValue("Preferences/Bittorrent/TrackersList", val);
}
qreal Preferences::getGlobalMaxRatio() const
{
return value("Preferences/Bittorrent/MaxRatio", -1).toDouble();
@@ -950,14 +1004,14 @@ void Preferences::setGlobalMaxRatio(qreal ratio)
setValue("Preferences/Bittorrent/MaxRatio", ratio);
}
int Preferences::getMaxRatioAction() const
MaxRatioAction Preferences::getMaxRatioAction() const
{
return value("Preferences/Bittorrent/MaxRatioAction", PAUSE_ACTION).toInt();
return value("Preferences/Bittorrent/MaxRatioAction", QVariant::fromValue(MaxRatioAction::Pause)).value<MaxRatioAction>();
}
void Preferences::setMaxRatioAction(int act)
void Preferences::setMaxRatioAction(MaxRatioAction act)
{
setValue("Preferences/Bittorrent/MaxRatioAction", act);
setValue("Preferences/Bittorrent/MaxRatioAction", QVariant::fromValue(act));
}
// IP Filter
@@ -983,12 +1037,12 @@ void Preferences::setFilteringTrackerEnabled(bool enabled)
QString Preferences::getFilter() const
{
return fsutils::fromNativePath(value("Preferences/IPFilter/File").toString());
return Utils::Fs::fromNativePath(value("Preferences/IPFilter/File").toString());
}
void Preferences::setFilter(const QString &path)
{
setValue("Preferences/IPFilter/File", fsutils::fromNativePath(path));
setValue("Preferences/IPFilter/File", Utils::Fs::fromNativePath(path));
}
QStringList Preferences::bannedIPs() const
@@ -1283,12 +1337,12 @@ void Preferences::setAutoRunEnabled(bool enabled)
QString Preferences::getAutoRunProgram() const
{
return fsutils::fromNativePath(value("AutoRun/program").toString());
return Utils::Fs::fromNativePath(value("AutoRun/program").toString());
}
void Preferences::setAutoRunProgram(const QString &program)
{
setValue("AutoRun/program", fsutils::fromNativePath(program));
setValue("AutoRun/program", Utils::Fs::fromNativePath(program));
}
bool Preferences::shutdownWhenDownloadsComplete() const
@@ -1334,37 +1388,26 @@ void Preferences::setShutdownqBTWhenDownloadsComplete(bool shutdown)
uint Preferences::diskCacheSize() const
{
uint size = value("Preferences/Downloads/DiskWriteCacheSize", 0).toUInt();
// When build as 32bit binary, set the maximum at less than 2GB to prevent crashes.
// These macros may not be available on compilers other than MSVC and GCC
#if !defined(_M_X64) && !defined(__amd64__)
//1800MiB to leave 248MiB room to the rest of program data in RAM
if (size > 1800)
size = 1800;
#if defined(__x86_64__) || defined(_M_X64)
size = qMin(size, (uint) 4096); // 4GiB
#else
// 4GiB
if (size > 4 * 1024)
size = 4 * 1024;
// When build as 32bit binary, set the maximum at less than 2GB to prevent crashes
// allocate 1536MiB and leave 512MiB to the rest of program data in RAM
size = qMin(size, (uint) 1536);
#endif
return size;
}
void Preferences::setDiskCacheSize(uint size)
{
uint size0 = size;
#if !defined(_M_X64) && !defined(__amd64__)
//1800MiB to leave 248MiB room to the rest of program data in RAM
if (size0 > 1800)
size0 = 1800;
#if defined(__x86_64__) || defined(_M_X64)
size = qMin(size, (uint) 4096); // 4GiB
#else
// 4GiB
if (size0 > 4 * 1024)
size0 = 4 * 1024;
// allocate 1536MiB and leave 512MiB to the rest of program data in RAM
size = qMin(size, (uint) 1536);
#endif
setValue("Preferences/Downloads/DiskWriteCacheSize", size0);
setValue("Preferences/Downloads/DiskWriteCacheSize", size);
}
uint Preferences::diskCacheTTL() const
@@ -1417,12 +1460,12 @@ void Preferences::setOutgoingPortsMax(uint val)
setValue("Preferences/Advanced/OutgoingPortsMax", val);
}
bool Preferences::ignoreLimitsOnLAN() const
bool Preferences::getIgnoreLimitsOnLAN() const
{
return value("Preferences/Advanced/IgnoreLimitsLAN", true).toBool();
}
void Preferences::ignoreLimitsOnLAN(bool ignore)
void Preferences::setIgnoreLimitsOnLAN(bool ignore)
{
setValue("Preferences/Advanced/IgnoreLimitsLAN", ignore);
}
@@ -1594,6 +1637,13 @@ void Preferences::setTorrentLabels(const QStringList& labels)
setValue("TransferListFilters/customLabels", labels);
}
void Preferences::addTorrentLabelExternal(const QString &label)
{
addTorrentLabel(label);
QString toEmit = label;
emit externalLabelAdded(toEmit);
}
void Preferences::addTorrentLabel(const QString& label)
{
QStringList labels = value("TransferListFilters/customLabels").toStringList();
@@ -1797,12 +1847,12 @@ bool Preferences::isMagnetLinkAssocSet()
// Check magnet link assoc
QRegExp exe_reg("\"([^\"]+)\".*");
QString shell_command = fsutils::toNativePath(settings.value("magnet/shell/open/command/Default", "").toString());
QString shell_command = Utils::Fs::toNativePath(settings.value("magnet/shell/open/command/Default", "").toString());
if (exe_reg.indexIn(shell_command) < 0)
return false;
QString assoc_exe = exe_reg.cap(1);
qDebug("exe: %s", qPrintable(assoc_exe));
if (assoc_exe.compare(fsutils::toNativePath(qApp->applicationFilePath()), Qt::CaseInsensitive) != 0)
if (assoc_exe.compare(Utils::Fs::toNativePath(qApp->applicationFilePath()), Qt::CaseInsensitive) != 0)
return false;
return true;
@@ -1838,9 +1888,9 @@ void Preferences::setMagnetLinkAssoc(bool set)
settings.setValue("magnet/Default", "URL:Magnet link");
settings.setValue("magnet/Content Type", "application/x-magnet");
settings.setValue("magnet/URL Protocol", "");
settings.setValue("magnet/DefaultIcon/Default", fsutils::toNativePath(icon_str));
settings.setValue("magnet/DefaultIcon/Default", Utils::Fs::toNativePath(icon_str));
settings.setValue("magnet/shell/Default", "open");
settings.setValue("magnet/shell/open/command/Default", fsutils::toNativePath(command_str));
settings.setValue("magnet/shell/open/command/Default", Utils::Fs::toNativePath(command_str));
}
else if (isMagnetLinkAssocSet()) {
settings.remove("magnet");
@@ -2197,36 +2247,36 @@ void Preferences::setRssOpenFolders(const QStringList &folders)
QByteArray Preferences::getRssHSplitterState() const
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
return value("rss/qt5/splitter_h").toByteArray();
return value("Rss/qt5/splitter_h").toByteArray();
#else
return value("rss/splitter_h").toByteArray();
return value("Rss/splitter_h").toByteArray();
#endif
}
void Preferences::setRssHSplitterState(const QByteArray &state)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
setValue("rss/qt5/splitter_h", state);
setValue("Rss/qt5/splitter_h", state);
#else
setValue("rss/splitter_h", state);
setValue("Rss/splitter_h", state);
#endif
}
QByteArray Preferences::getRssVSplitterState() const
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
return value("rss/qt5/splitter_v").toByteArray();
return value("Rss/qt5/splitter_v").toByteArray();
#else
return value("rss/splitter_v").toByteArray();
return value("Rss/splitter_v").toByteArray();
#endif
}
void Preferences::setRssVSplitterState(const QByteArray &state)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
setValue("rss/qt5/splitter_v", state);
setValue("Rss/qt5/splitter_v", state);
#else
setValue("rss/splitter_v", state);
setValue("Rss/splitter_v", state);
#endif
}
@@ -2498,3 +2548,28 @@ void Preferences::setHostNameCookies(const QString &host_name, const QList<QByte
hosts_table.insert(host_name, raw_cookies);
setValue("Rss/hosts_cookies", hosts_table);
}
int Preferences::getSpeedWidgetPeriod() const {
return value("SpeedWidget/period", 1).toInt();
}
void Preferences::setSpeedWidgetPeriod(const int period) {
setValue("SpeedWidget/period", period);
}
bool Preferences::getSpeedWidgetGraphEnable(int id) const
{
// UP and DOWN graphs enabled by default
return value("SpeedWidget/graph_enable_" + QString::number(id), (id == 0 || id == 1)).toBool();
}
void Preferences::setSpeedWidgetGraphEnable(int id, const bool enable)
{
setValue("SpeedWidget/graph_enable_" + QString::number(id), enable);
}
void Preferences::apply()
{
if (save())
emit changed();
}

View File

@@ -41,7 +41,7 @@
#include <QNetworkCookie>
#include <QVariant>
#include <libtorrent/version.hpp>
#include "core/types.h"
enum scheduler_days
{
@@ -57,12 +57,6 @@ enum scheduler_days
SUN
};
enum maxRatioAction
{
PAUSE_ACTION,
REMOVE_ACTION
};
namespace Proxy
{
enum ProxyType
@@ -101,7 +95,9 @@ class Preferences: public QObject
Q_DISABLE_COPY(Preferences)
private:
explicit Preferences();
Preferences();
~Preferences();
static Preferences* m_instance;
QHash<QString, QVariant> m_data;
int m_randomPort;
@@ -111,16 +107,17 @@ private:
const QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
void setValue(const QString &key, const QVariant &value);
private slots:
bool save();
signals:
void changed();
public slots:
void save();
void externalLabelAdded(QString&);
public:
static void initInstance();
static void freeInstance();
static Preferences* instance();
static void drop();
~Preferences();
// General options
QString getLocale() const;
@@ -182,6 +179,8 @@ public:
QList<bool> getDownloadInScanDirs() const;
void setDownloadInScanDirs(const QList<bool> &list);
QString getScanDirsLastPath() const;
void setScanDirsDownloadPaths(const QStringList &downloadpaths);
QStringList getScanDirsDownloadPaths() const;
void setScanDirsLastPath(const QString &path);
bool isTorrentExportEnabled() const;
QString getTorrentExportDir() const;
@@ -248,10 +247,10 @@ public:
void setProxyType(int type);
bool proxyPeerConnections() const;
void setProxyPeerConnections(bool enabled);
#if LIBTORRENT_VERSION_NUM >= 10000
bool getForceProxy() const;
void setForceProxy(bool enabled);
#endif
void setProxyOnlyForTorrents(bool enabled);
bool isProxyOnlyForTorrents() const;
// Bittorrent options
int getMaxConnecs() const;
@@ -274,10 +273,14 @@ public:
void setLSDEnabled(bool enabled);
int getEncryptionSetting() const;
void setEncryptionSetting(int val);
bool isAddTrackersEnabled() const;
void setAddTrackersEnabled(bool enabled);
QString getTrackersList() const;
void setTrackersList(const QString &val);
qreal getGlobalMaxRatio() const;
void setGlobalMaxRatio(qreal ratio);
int getMaxRatioAction() const;
void setMaxRatioAction(int act);
MaxRatioAction getMaxRatioAction() const;
void setMaxRatioAction(MaxRatioAction act);
// IP Filter
bool isFilteringEnabled() const;
@@ -367,8 +370,8 @@ public:
void setOutgoingPortsMin(uint val);
uint outgoingPortsMax() const;
void setOutgoingPortsMax(uint val);
bool ignoreLimitsOnLAN() const;
void ignoreLimitsOnLAN(bool ignore);
bool getIgnoreLimitsOnLAN() const;
void setIgnoreLimitsOnLAN(bool ignore);
bool includeOverheadInLimits() const;
void includeOverheadInLimits(bool include);
bool trackerExchangeEnabled() const;
@@ -403,6 +406,7 @@ public:
#endif
QStringList getTorrentLabels() const;
void setTorrentLabels(const QStringList& labels);
void addTorrentLabelExternal(const QString &label);
void addTorrentLabel(const QString& label);
void removeTorrentLabel(const QString& label);
bool recursiveDownloadDisabled() const;
@@ -536,10 +540,18 @@ public:
QList<QNetworkCookie> getHostNameQNetworkCookies(const QString& host_name) const;
void setHostNameCookies(const QString &host_name, const QList<QByteArray> &cookies);
// SpeedWidget
int getSpeedWidgetPeriod() const;
void setSpeedWidgetPeriod(const int period);
bool getSpeedWidgetGraphEnable(int id) const;
void setSpeedWidgetGraphEnable(int id, const bool enable);
public slots:
void setStatusFilterState(bool checked);
void setLabelFilterState(bool checked);
void setTrackerFilterState(bool checked);
void apply();
};
#endif // PREFERENCES_H

View File

@@ -1,132 +0,0 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2014 Ivan Sorokin
*
* 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.
*
* Contact : vanyacpp@gmail.com
*/
#include "alertdispatcher.h"
#include <libtorrent/session.hpp>
#include <boost/bind.hpp>
#include <QMutexLocker>
const size_t DEFAULT_ALERTS_CAPACITY = 32;
struct QAlertDispatcher::Tag {
Tag(QAlertDispatcher* dispatcher);
QAlertDispatcher* dispatcher;
QMutex alerts_mutex;
};
QAlertDispatcher::Tag::Tag(QAlertDispatcher* dispatcher)
: dispatcher(dispatcher)
{}
QAlertDispatcher::QAlertDispatcher(libtorrent::session *session, QObject* parent)
: QObject(parent)
, m_session(session)
, current_tag(new Tag(this))
, event_posted(false)
{
alerts.reserve(DEFAULT_ALERTS_CAPACITY);
m_session->set_alert_dispatch(boost::bind(&QAlertDispatcher::dispatch, current_tag, _1));
}
QAlertDispatcher::~QAlertDispatcher() {
// When QAlertDispatcher is destoyed, libtorrent still can call
// QAlertDispatcher::dispatch a few times after destruction. This is
// handled by passing a "tag". A tag is a object that references QAlertDispatch.
// Tag could be invalidated. So on destruction QAlertDispatcher invalidates a tag
// and then unsubscribes from alerts. When QAlertDispatcher::dispatch is called
// with invalid tag it simply discard an alert.
{
QMutexLocker lock(&current_tag->alerts_mutex);
current_tag->dispatcher = 0;
current_tag.clear();
}
typedef boost::function<void (std::auto_ptr<libtorrent::alert>)> dispatch_function_t;
m_session->set_alert_dispatch(dispatch_function_t());
}
void QAlertDispatcher::getPendingAlertsNoWait(std::vector<libtorrent::alert*>& out) {
Q_ASSERT(out.empty());
out.reserve(DEFAULT_ALERTS_CAPACITY);
QMutexLocker lock(&current_tag->alerts_mutex);
alerts.swap(out);
event_posted = false;
}
void QAlertDispatcher::getPendingAlerts(std::vector<libtorrent::alert*>& out, unsigned long time) {
Q_ASSERT(out.empty());
out.reserve(DEFAULT_ALERTS_CAPACITY);
QMutexLocker lock(&current_tag->alerts_mutex);
while (alerts.empty())
alerts_condvar.wait(&current_tag->alerts_mutex, time);
alerts.swap(out);
event_posted = false;
}
void QAlertDispatcher::dispatch(QSharedPointer<Tag> tag,
std::auto_ptr<libtorrent::alert> alert_ptr) {
QMutexLocker lock(&(tag->alerts_mutex));
QAlertDispatcher* that = tag->dispatcher;
if (!that)
return;
bool was_empty = that->alerts.empty();
that->alerts.push_back(alert_ptr.release());
if (was_empty)
that->alerts_condvar.wakeAll();
that->enqueueToMainThread();
Q_ASSERT(that->current_tag == tag);
}
void QAlertDispatcher::enqueueToMainThread() {
if (!event_posted) {
event_posted = true;
QMetaObject::invokeMethod(this, "deliverSignal", Qt::QueuedConnection);
}
}
void QAlertDispatcher::deliverSignal() {
emit alertsReceived();
QMutexLocker lock(&current_tag->alerts_mutex);
event_posted = false;
if (!alerts.empty())
enqueueToMainThread();
}

View File

@@ -1,79 +0,0 @@
#ifndef BANDWIDTHSCHEDULER_H
#define BANDWIDTHSCHEDULER_H
#include <QTimer>
#include <QTime>
#include <QDateTime>
#include "preferences.h"
#include <iostream>
class BandwidthScheduler: public QTimer {
Q_OBJECT
public:
BandwidthScheduler(QObject *parent): QTimer(parent) {
Q_ASSERT(Preferences::instance()->isSchedulerEnabled());
// Signal shot, we call start() again manually
setSingleShot(true);
// Connect Signals/Slots
connect(this, SIGNAL(timeout()), this, SLOT(start()));
}
public slots:
void start() {
const Preferences* const pref = Preferences::instance();
Q_ASSERT(pref->isSchedulerEnabled());
bool alt_bw_enabled = pref->isAltBandwidthEnabled();
QTime start = pref->getSchedulerStartTime();
QTime end = pref->getSchedulerEndTime();
QTime now = QTime::currentTime();
int sched_days = pref->getSchedulerDays();
int day = QDateTime::currentDateTime().toLocalTime().date().dayOfWeek();
bool new_mode = false;
bool reverse = false;
if (start > end) {
QTime temp = start;
start = end;
end = temp;
reverse = true;
}
if (start <= now && end >= now) {
switch(sched_days) {
case EVERY_DAY:
new_mode = true;
break;
case WEEK_ENDS:
if (day == 6 || day == 7)
new_mode = true;
break;
case WEEK_DAYS:
if (day != 6 && day != 7)
new_mode = true;
break;
default:
if (day == sched_days - 2)
new_mode = true;
break;
}
}
if (reverse)
new_mode = !new_mode;
if (new_mode != alt_bw_enabled)
emit switchToAlternativeMode(new_mode);
// Timeout regularly to accomodate for external system clock changes
// eg from the user or from a timesync utility
QTimer::start(1500);
}
signals:
void switchToAlternativeMode(bool alternative);
};
#endif // BANDWIDTHSCHEDULER_H

View File

@@ -1,394 +0,0 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* 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
* 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.
*
* Contact : chris@qbittorrent.org
*/
#include "filterparserthread.h"
#include <QFile>
#include <QHostAddress>
#include <libtorrent/session.hpp>
#include <libtorrent/ip_filter.hpp>
FilterParserThread::FilterParserThread(QObject* parent, libtorrent::session *s) : QThread(parent), s(s), abort(false) {
}
FilterParserThread::~FilterParserThread() {
abort = true;
wait();
}
// Parser for eMule ip filter in DAT format
int FilterParserThread::parseDATFilterFile(QString filePath, libtorrent::ip_filter& filter) {
int ruleCount = 0;
QFile file(filePath);
if (file.exists()) {
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl;
return ruleCount;
}
unsigned int nbLine = 0;
while (!file.atEnd() && !abort) {
++nbLine;
QByteArray line = file.readLine();
// Ignoring empty lines
line = line.trimmed();
if (line.isEmpty()) continue;
// Ignoring commented lines
if (line.startsWith('#') || line.startsWith("//")) continue;
// Line should be splitted by commas
QList<QByteArray> partsList = line.split(',');
const uint nbElem = partsList.size();
// IP Range should be splitted by a dash
QList<QByteArray> IPs = partsList.first().split('-');
if (IPs.size() != 2) {
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
qDebug("Line was %s", line.constData());
continue;
}
boost::system::error_code ec;
const QString strStartIP = cleanupIPAddress(IPs.at(0));
if (strStartIP.isEmpty()) {
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
qDebug("Start IP of the range is malformated: %s", qPrintable(strStartIP));
continue;
}
libtorrent::address startAddr = libtorrent::address::from_string(qPrintable(strStartIP), ec);
if (ec) {
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
qDebug("Start IP of the range is malformated: %s", qPrintable(strStartIP));
continue;
}
const QString strEndIP = cleanupIPAddress(IPs.at(1));
if (strEndIP.isEmpty()) {
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
qDebug("End IP of the range is malformated: %s", qPrintable(strEndIP));
continue;
}
libtorrent::address endAddr = libtorrent::address::from_string(qPrintable(strEndIP), ec);
if (ec) {
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
qDebug("End IP of the range is malformated: %s", qPrintable(strEndIP));
continue;
}
if (startAddr.is_v4() != endAddr.is_v4()) {
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
qDebug("One IP is IPv4 and the other is IPv6!");
continue;
}
// Check if there is an access value (apparently not mandatory)
int nbAccess = 0;
if (nbElem > 1) {
// There is possibly one
nbAccess = partsList.at(1).trimmed().toInt();
}
if (nbAccess > 127) {
// Ignoring this rule because access value is too high
continue;
}
// Now Add to the filter
try {
filter.add_rule(startAddr, endAddr, libtorrent::ip_filter::blocked);
++ruleCount;
}catch(exception) {
qDebug("Bad line in filter file, avoided crash...");
}
}
file.close();
}
return ruleCount;
}
// Parser for PeerGuardian ip filter in p2p format
int FilterParserThread::parseP2PFilterFile(QString filePath, libtorrent::ip_filter& filter) {
int ruleCount = 0;
QFile file(filePath);
if (file.exists()) {
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl;
return ruleCount;
}
unsigned int nbLine = 0;
while (!file.atEnd() && !abort) {
++nbLine;
QByteArray line = file.readLine().trimmed();
if (line.isEmpty()) continue;
// Ignoring commented lines
if (line.startsWith('#') || line.startsWith("//")) continue;
// Line is splitted by :
QList<QByteArray> partsList = line.split(':');
if (partsList.size() < 2) {
qDebug("p2p file: line %d is malformed.", nbLine);
continue;
}
// Get IP range
QList<QByteArray> IPs = partsList.last().split('-');
if (IPs.size() != 2) {
qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("line was: %s", line.constData());
continue;
}
boost::system::error_code ec;
QString strStartIP = cleanupIPAddress(IPs.at(0));
if (strStartIP.isEmpty()) {
qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("Start IP is invalid: %s", qPrintable(strStartIP));
continue;
}
libtorrent::address startAddr = libtorrent::address::from_string(qPrintable(strStartIP), ec);
if (ec) {
qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("Start IP is invalid: %s", qPrintable(strStartIP));
continue;
}
QString strEndIP = cleanupIPAddress(IPs.at(1));
if (strEndIP.isEmpty()) {
qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("End IP is invalid: %s", qPrintable(strStartIP));
continue;
}
libtorrent::address endAddr = libtorrent::address::from_string(qPrintable(strEndIP), ec);
if (ec) {
qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("End IP is invalid: %s", qPrintable(strStartIP));
continue;
}
if (startAddr.is_v4() != endAddr.is_v4()) {
qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("Line was: %s", line.constData());
continue;
}
try {
filter.add_rule(startAddr, endAddr, libtorrent::ip_filter::blocked);
++ruleCount;
} catch(std::exception&) {
qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("Line was: %s", line.constData());
continue;
}
}
file.close();
}
return ruleCount;
}
int FilterParserThread::getlineInStream(QDataStream& stream, string& name, char delim) {
char c;
int total_read = 0;
int read;
do {
read = stream.readRawData(&c, 1);
total_read += read;
if (read > 0) {
if (c != delim) {
name += c;
} else {
// Delim found
return total_read;
}
}
} while(read > 0);
return total_read;
}
// Parser for PeerGuardian ip filter in p2p format
int FilterParserThread::parseP2BFilterFile(QString filePath, libtorrent::ip_filter& filter) {
int ruleCount = 0;
QFile file(filePath);
if (file.exists()) {
if (!file.open(QIODevice::ReadOnly)) {
std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl;
return ruleCount;
}
QDataStream stream(&file);
// Read header
char buf[7];
unsigned char version;
if (
!stream.readRawData(buf, sizeof(buf)) ||
memcmp(buf, "\xFF\xFF\xFF\xFFP2B", 7) ||
!stream.readRawData((char*)&version, sizeof(version))
) {
std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl;
return ruleCount;
}
if (version==1 || version==2) {
qDebug ("p2b version 1 or 2");
unsigned int start, end;
string name;
while(getlineInStream(stream, name, '\0') && !abort) {
if (
!stream.readRawData((char*)&start, sizeof(start)) ||
!stream.readRawData((char*)&end, sizeof(end))
) {
std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl;
return ruleCount;
}
// Network byte order to Host byte order
// asio address_v4 contructor expects it
// that way
libtorrent::address_v4 first(ntohl(start));
libtorrent::address_v4 last(ntohl(end));
// Apply to bittorrent session
try {
filter.add_rule(first, last, libtorrent::ip_filter::blocked);
++ruleCount;
} catch(std::exception&) {}
}
}
else if (version==3) {
qDebug ("p2b version 3");
unsigned int namecount;
if (!stream.readRawData((char*)&namecount, sizeof(namecount))) {
std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl;
return ruleCount;
}
namecount=ntohl(namecount);
// Reading names although, we don't really care about them
for (unsigned int i=0; i<namecount; i++) {
string name;
if (!getlineInStream(stream, name, '\0')) {
std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl;
return ruleCount;
}
if (abort) return ruleCount;
}
// Reading the ranges
unsigned int rangecount;
if (!stream.readRawData((char*)&rangecount, sizeof(rangecount))) {
std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl;
return ruleCount;
}
rangecount=ntohl(rangecount);
unsigned int name, start, end;
for (unsigned int i=0; i<rangecount; i++) {
if (
!stream.readRawData((char*)&name, sizeof(name)) ||
!stream.readRawData((char*)&start, sizeof(start)) ||
!stream.readRawData((char*)&end, sizeof(end))
) {
std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl;
return ruleCount;
}
// Network byte order to Host byte order
// asio address_v4 contructor expects it
// that way
libtorrent::address_v4 first(ntohl(start));
libtorrent::address_v4 last(ntohl(end));
// Apply to bittorrent session
try {
filter.add_rule(first, last, libtorrent::ip_filter::blocked);
++ruleCount;
} catch(std::exception&) {}
if (abort) return ruleCount;
}
} else {
std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl;
return ruleCount;
}
file.close();
}
return ruleCount;
}
// Process ip filter file
// Supported formats:
// * eMule IP list (DAT): http://wiki.phoenixlabs.org/wiki/DAT_Format
// * PeerGuardian Text (P2P): http://wiki.phoenixlabs.org/wiki/P2P_Format
// * PeerGuardian Binary (P2B): http://wiki.phoenixlabs.org/wiki/P2B_Format
void FilterParserThread::processFilterFile(QString _filePath) {
if (isRunning()) {
// Already parsing a filter, abort first
abort = true;
wait();
}
abort = false;
filePath = _filePath;
// Run it
start();
}
void FilterParserThread::processFilterList(libtorrent::session *s, const QStringList& IPs) {
// First, import current filter
libtorrent::ip_filter filter = s->get_ip_filter();
foreach (const QString &ip, IPs) {
qDebug("Manual ban of peer %s", ip.toLocal8Bit().constData());
boost::system::error_code ec;
libtorrent::address addr = libtorrent::address::from_string(ip.toLocal8Bit().constData(), ec);
Q_ASSERT(!ec);
if (!ec)
filter.add_rule(addr, addr, libtorrent::ip_filter::blocked);
}
s->set_ip_filter(filter);
}
QString FilterParserThread::cleanupIPAddress(QString _ip) {
QHostAddress ip(_ip.trimmed());
if (ip.isNull()) {
return QString();
}
return ip.toString();
}
void FilterParserThread::run() {
qDebug("Processing filter file");
libtorrent::ip_filter filter = s->get_ip_filter();
int ruleCount = 0;
if (filePath.endsWith(".p2p", Qt::CaseInsensitive)) {
// PeerGuardian p2p file
ruleCount = parseP2PFilterFile(filePath, filter);
} else {
if (filePath.endsWith(".p2b", Qt::CaseInsensitive)) {
// PeerGuardian p2b file
ruleCount = parseP2BFilterFile(filePath, filter);
} else {
// Default: eMule DAT format
ruleCount = parseDATFilterFile(filePath, filter);
}
}
if (abort)
return;
try {
s->set_ip_filter(filter);
emit IPFilterParsed(ruleCount);
} catch(std::exception&) {
emit IPFilterError();
}
qDebug("IP Filter thread: finished parsing, filter applied");
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,352 +0,0 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* 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
* 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.
*
* Contact : chris@qbittorrent.org
*/
#ifndef __BITTORRENT_H__
#define __BITTORRENT_H__
#include <QMap>
#include <QHash>
#include <QUrl>
#include <QStringList>
#include <QPointer>
#include <QTimer>
#include <QNetworkCookie>
#include <libtorrent/version.hpp>
#include "qtorrenthandle.h"
#include "trackerinfos.h"
#include "misc.h"
#ifndef DISABLE_GUI
#include "rssdownloadrule.h"
#endif
namespace libtorrent {
struct add_torrent_params;
struct pe_settings;
struct proxy_settings;
class session;
struct session_status;
class alert;
struct torrent_finished_alert;
struct save_resume_data_alert;
struct file_renamed_alert;
struct torrent_deleted_alert;
struct storage_moved_alert;
struct storage_moved_failed_alert;
struct metadata_received_alert;
struct file_error_alert;
struct file_completed_alert;
struct torrent_paused_alert;
struct tracker_error_alert;
struct tracker_reply_alert;
struct tracker_warning_alert;
struct portmap_error_alert;
struct portmap_alert;
struct peer_blocked_alert;
struct peer_ban_alert;
struct fastresume_rejected_alert;
struct url_seed_alert;
struct listen_succeeded_alert;
struct listen_failed_alert;
struct torrent_checked_alert;
struct external_ip_alert;
struct state_update_alert;
struct stats_alert;
#if LIBTORRENT_VERSION_NUM < 10000
class upnp;
class natpmp;
#endif
}
class DownloadThread;
class FilterParserThread;
class BandwidthScheduler;
class ScanFoldersModel;
class TorrentSpeedMonitor;
class TorrentStatistics;
class QAlertDispatcher;
enum TorrentExportFolder {
RegularTorrentExportFolder,
FinishedTorrentExportFolder
};
class QTracker;
class QBtSession : public QObject {
Q_OBJECT
Q_DISABLE_COPY(QBtSession)
public:
static const qreal MAX_RATIO;
private:
explicit QBtSession();
static QBtSession* m_instance;
public:
static QBtSession* instance();
static void drop();
~QBtSession();
QTorrentHandle getTorrentHandle(const QString &hash) const;
std::vector<libtorrent::torrent_handle> getTorrents() const;
qreal getPayloadDownloadRate() const;
qreal getPayloadUploadRate() const;
libtorrent::session_status getSessionStatus() const;
int getListenPort() const;
qreal getRealRatio(const libtorrent::torrent_status &status) const;
QHash<QString, TrackerInfos> getTrackersInfo(const QString &hash) const;
bool hasActiveTorrents() const;
bool hasDownloadingTorrents() const;
//int getMaximumActiveDownloads() const;
//int getMaximumActiveTorrents() const;
inline libtorrent::session* getSession() const { return s; }
inline bool useTemporaryFolder() const { return !defaultTempPath.isEmpty(); }
inline QString getDefaultSavePath() const { return defaultSavePath; }
inline ScanFoldersModel* getScanFoldersModel() const { return m_scanFolders; }
inline bool isDHTEnabled() const { return DHTEnabled; }
inline bool isLSDEnabled() const { return LSDEnabled; }
inline bool isPexEnabled() const { return PeXEnabled; }
inline bool isQueueingEnabled() const { return queueingEnabled; }
quint64 getAlltimeDL() const;
quint64 getAlltimeUL() const;
void postTorrentUpdate();
public slots:
QTorrentHandle addTorrent(QString path, bool fromScanDir = false, QString from_url = QString(), bool resumed = false, bool imported = false);
QTorrentHandle addMagnetUri(QString magnet_uri, bool resumed=false, bool fromScanDir=false, const QString &filePath=QString());
void loadSessionState();
void saveSessionState();
void downloadFromUrl(const QString &url, const QList<QNetworkCookie>& cookies = QList<QNetworkCookie>());
void deleteTorrent(const QString &hash, bool delete_local_files = false);
void startUpTorrents();
void recheckTorrent(const QString &hash);
void useAlternativeSpeedsLimit(bool alternative);
qlonglong getETA(const QString& hash, const libtorrent::torrent_status &status) const;
/* Needed by Web UI */
void pauseAllTorrents();
void pauseTorrent(const QString &hash);
void resumeTorrent(const QString &hash, const bool force = false);
void resumeAllTorrents();
/* End Web UI */
void preAllocateAllFiles(bool b);
void saveFastResumeData();
void enableIPFilter(const QString &filter_path, bool force=false);
void disableIPFilter();
void setQueueingEnabled(bool enable);
void handleDownloadFailure(QString url, QString reason);
void handleMagnetRedirect(const QString &url_new, const QString &url_old);
#ifndef DISABLE_GUI
void downloadUrlAndSkipDialog(QString url, QString save_path=QString(), QString label=QString(),
const QList<QNetworkCookie>& cookies = QList<QNetworkCookie>(),
const RssDownloadRule::AddPausedState &aps = RssDownloadRule::USE_GLOBAL);
#else
void downloadUrlAndSkipDialog(QString url, QString save_path=QString(), QString label=QString(),
const QList<QNetworkCookie>& cookies = QList<QNetworkCookie>());
#endif
// Session configuration - Setters
void setListeningPort(int port);
void setMaxConnectionsPerTorrent(int max);
void setMaxUploadsPerTorrent(int max);
void setDownloadRateLimit(long rate);
void setUploadRateLimit(long rate);
void setGlobalMaxRatio(qreal ratio);
qreal getGlobalMaxRatio() const { return global_ratio_limit; }
void setMaxRatioPerTorrent(const QString &hash, qreal ratio);
qreal getMaxRatioPerTorrent(const QString &hash, bool *usesGlobalRatio) const;
void removeRatioPerTorrent(const QString &hash);
void setDefaultSavePath(const QString &savepath);
void setDefaultTempPath(const QString &temppath);
void setAppendLabelToSavePath(bool append);
void appendLabelToTorrentSavePath(const QTorrentHandle &h);
void changeLabelInTorrentSavePath(const QTorrentHandle &h, QString old_label, QString new_label);
void appendqBextensionToTorrent(const QTorrentHandle &h, bool append);
void setAppendqBExtension(bool append);
void setDownloadLimit(QString hash, long val);
void setUploadLimit(QString hash, long val);
void enableUPnP(bool b);
void enableLSD(bool b);
void enableDHT(bool b);
void processDownloadedFile(QString, QString);
#ifndef DISABLE_GUI
void addMagnetSkipAddDlg(const QString& uri, const QString& save_path = QString(), const QString& label = QString(),
const RssDownloadRule::AddPausedState &aps = RssDownloadRule::USE_GLOBAL, const QString &uri_old = QString());
#else
void addMagnetSkipAddDlg(const QString& uri, const QString& save_path = QString(), const QString& label = QString(), const QString &uri_old = QString());
#endif
void addMagnetInteractive(const QString& uri);
void downloadFromURLList(const QStringList& urls);
void banIP(QString ip);
void recursiveTorrentDownload(const QTorrentHandle &h);
void unhideMagnet(const QString &hash);
void addTrackersAndUrlSeeds(const QString &hash, const QStringList &trackers, const QStringList& urlSeeds);
private:
void applyEncryptionSettings(libtorrent::pe_settings se);
void setProxySettings(libtorrent::proxy_settings proxySettings);
void setSessionSettings(const libtorrent::session_settings &sessionSettings);
QString getSavePath(const QString &hash, bool fromScanDir = false, QString filePath = QString::null, bool imported = false);
bool loadFastResumeData(const QString &hash, std::vector<char> &buf);
void loadTorrentSettings(QTorrentHandle &h);
void loadTorrentTempData(QTorrentHandle &h, QString savePath, bool magnet);
void initializeAddTorrentParams(const QString &hash, libtorrent::add_torrent_params &p);
void updateRatioTimer();
void recoverPersistentData(const QString &hash, const std::vector<char> &buf);
void backupPersistentData(const QString &hash, boost::shared_ptr<libtorrent::entry> data);
void handleAlert(libtorrent::alert* a);
void handleTorrentFinishedAlert(libtorrent::torrent_finished_alert* p);
void handleSaveResumeDataAlert(libtorrent::save_resume_data_alert* p);
void handleFileRenamedAlert(libtorrent::file_renamed_alert* p);
void handleTorrentDeletedAlert(libtorrent::torrent_deleted_alert* p);
void handleStorageMovedAlert(libtorrent::storage_moved_alert* p);
void handleStorageMovedFailedAlert(libtorrent::storage_moved_failed_alert* p);
void handleMetadataReceivedAlert(libtorrent::metadata_received_alert* p);
void handleFileErrorAlert(libtorrent::file_error_alert* p);
void handleFileCompletedAlert(libtorrent::file_completed_alert* p);
void handleTorrentPausedAlert(libtorrent::torrent_paused_alert* p);
void handleTrackerErrorAlert(libtorrent::tracker_error_alert* p);
void handleTrackerReplyAlert(libtorrent::tracker_reply_alert* p);
void handleTrackerWarningAlert(libtorrent::tracker_warning_alert* p);
void handlePortmapWarningAlert(libtorrent::portmap_error_alert* p);
void handlePortmapAlert(libtorrent::portmap_alert* p);
void handlePeerBlockedAlert(libtorrent::peer_blocked_alert* p);
void handlePeerBanAlert(libtorrent::peer_ban_alert* p);
void handleFastResumeRejectedAlert(libtorrent::fastresume_rejected_alert* p);
void handleUrlSeedAlert(libtorrent::url_seed_alert* p);
void handleListenSucceededAlert(libtorrent::listen_succeeded_alert *p);
void handleListenFailedAlert(libtorrent::listen_failed_alert *p);
void handleTorrentCheckedAlert(libtorrent::torrent_checked_alert* p);
void handleExternalIPAlert(libtorrent::external_ip_alert *p);
void handleStateUpdateAlert(libtorrent::state_update_alert *p);
void handleStatsAlert(libtorrent::stats_alert *p);
private slots:
void addTorrentsFromScanFolder(QStringList&);
void readAlerts();
void processBigRatios();
void exportTorrentFiles(QString path);
void saveTempFastResumeData();
void sendNotificationEmail(const QTorrentHandle &h);
void autoRunExternalProgram(const QTorrentHandle &h);
void mergeTorrents(const QTorrentHandle &h, const boost::intrusive_ptr<libtorrent::torrent_info> t);
void mergeTorrents(const QTorrentHandle &h, const QString &magnet_uri);
void mergeTorrents_impl(const QTorrentHandle &h, const QStringList &trackers, const QStringList& urlSeeds);
void exportTorrentFile(const QTorrentHandle &h, TorrentExportFolder folder = RegularTorrentExportFolder);
void handleIPFilterParsed(int ruleCount);
void handleIPFilterError();
void configureSession();
signals:
void addedTorrent(const QTorrentHandle& h);
void torrentAboutToBeRemoved(const QTorrentHandle &h);
void pausedTorrent(const QTorrentHandle& h);
void resumedTorrent(const QTorrentHandle& h);
void finishedTorrent(const QTorrentHandle& h);
void fullDiskError(const QTorrentHandle& h, QString msg);
void trackerSuccess(const QString &hash, const QString &tracker);
void trackerError(const QString &hash, const QString &tracker);
void trackerWarning(const QString &hash, const QString &tracker);
void trackerAuthenticationRequired(const QTorrentHandle& h);
void newDownloadedTorrent(QString path, QString url);
void newDownloadedTorrentFromRss(QString url);
void newMagnetLink(const QString& link);
void updateFileSize(const QString &hash);
void downloadFromUrlFailure(QString url, QString reason);
void torrentFinishedChecking(const QTorrentHandle& h);
void metadataReceived(const QTorrentHandle &h);
void savePathChanged(const QTorrentHandle &h);
void alternativeSpeedsModeChanged(bool alternative);
void recursiveTorrentDownloadPossible(const QTorrentHandle &h);
void ipFilterParsed(bool error, int ruleCount);
void metadataReceivedHidden(const QTorrentHandle &h);
void stateUpdate(const std::vector<libtorrent::torrent_status> &statuses);
void statsReceived(const libtorrent::stats_alert&);
void trackersAdded(const QStringList &trackers, const QString &hash);
void trackerlessChange(bool trackerless, const QString &hash);
void reloadTrackersAndUrlSeeds(const QTorrentHandle &h);
private:
// Bittorrent
libtorrent::session *s;
QPointer<BandwidthScheduler> bd_scheduler;
QMap<QUrl, QPair<QString, QString> > savepathLabel_fromurl; // Use QMap for compatibility with Qt < 4.7: qHash(QUrl)
#ifndef DISABLE_GUI
QMap<QUrl, RssDownloadRule::AddPausedState> addpaused_fromurl;
#endif
QHash<QString, QHash<QString, TrackerInfos> > trackersInfos;
QHash<QString, QString> savePathsToRemove;
QStringList torrentsToPausedAfterChecking;
QTimer resumeDataTimer;
// Ratio
QPointer<QTimer> BigRatioTimer;
// HTTP
DownloadThread* downloader;
// File System
ScanFoldersModel *m_scanFolders;
// Settings
bool preAllocateAll;
qreal global_ratio_limit;
int high_ratio_action;
bool LSDEnabled;
bool DHTEnabled;
bool PeXEnabled;
bool queueingEnabled;
bool appendLabelToSavePath;
bool m_torrentExportEnabled;
bool m_finishedTorrentExportEnabled;
bool appendqBExtension;
QString defaultSavePath;
QString defaultTempPath;
// IP filtering
QPointer<FilterParserThread> filterParser;
QString filterPath;
QList<QUrl> url_skippingDlg;
// GeoIP
#ifndef DISABLE_GUI
bool geoipDBLoaded;
bool resolve_countries;
#endif
// Tracker
QPointer<QTracker> m_tracker;
TorrentSpeedMonitor *m_speedMonitor;
shutDownAction m_shutdownAct;
// Port forwarding
#if LIBTORRENT_VERSION_NUM < 10000
libtorrent::upnp *m_upnp;
libtorrent::natpmp *m_natpmp;
#endif
QAlertDispatcher* m_alertDispatcher;
TorrentStatistics* m_torrentStatistics;
};
#endif

View File

@@ -1,25 +0,0 @@
INCLUDEPATH += $$PWD
HEADERS += $$PWD/qbtsession.h \
$$PWD/qtorrenthandle.h \
$$PWD/bandwidthscheduler.h \
$$PWD/trackerinfos.h \
$$PWD/torrentspeedmonitor.h \
$$PWD/filterparserthread.h \
$$PWD/alertdispatcher.h \
$$PWD/torrentstatistics.h
SOURCES += $$PWD/qbtsession.cpp \
$$PWD/qtorrenthandle.cpp \
$$PWD/torrentspeedmonitor.cpp \
$$PWD/alertdispatcher.cpp \
$$PWD/torrentstatistics.cpp \
$$PWD/filterparserthread.cpp
!contains(DEFINES, DISABLE_GUI) {
HEADERS += $$PWD/torrentmodel.h \
$$PWD/shutdownconfirm.h
SOURCES += $$PWD/torrentmodel.cpp \
$$PWD/shutdownconfirm.cpp
}

View File

@@ -1,857 +0,0 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* 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
* 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.
*
* Contact : chris@qbittorrent.org
*/
#include <QDebug>
#include <QString>
#include <QStringList>
#include <QFile>
#include <QDir>
#include <QByteArray>
#include <math.h>
#include "fs_utils.h"
#include "misc.h"
#include "preferences.h"
#include "qtorrenthandle.h"
#include "torrentpersistentdata.h"
#include "qbtsession.h"
#include <libtorrent/version.hpp>
#include <libtorrent/magnet_uri.hpp>
#include <libtorrent/torrent_info.hpp>
#include <libtorrent/bencode.hpp>
#include <libtorrent/entry.hpp>
#ifdef Q_OS_WIN
#include <Windows.h>
#endif
using namespace libtorrent;
using namespace std;
static QPair<int, int> get_file_extremity_pieces(const torrent_info& t, int file_index)
{
const int num_pieces = t.num_pieces();
const int piece_size = t.piece_length();
const file_entry& file = t.file_at(file_index);
// Determine the first and last piece of the file
int first_piece = floor((file.offset + 1) / (float) piece_size);
Q_ASSERT(first_piece >= 0 && first_piece < num_pieces);
int num_pieces_in_file = ceil(file.size / (float) piece_size);
int last_piece = first_piece + num_pieces_in_file - 1;
Q_ASSERT(last_piece >= 0 && last_piece < num_pieces);
return qMakePair(first_piece, last_piece);
}
QTorrentHandle::QTorrentHandle(const torrent_handle& h): torrent_handle(h)
{
}
//
// Getters
//
QString QTorrentHandle::hash() const
{
return misc::toQString(torrent_handle::info_hash());
}
QString QTorrentHandle::name() const
{
QString name = TorrentPersistentData::instance()->getName(hash());
if (name.isEmpty()) {
#if LIBTORRENT_VERSION_NUM < 10000
name = misc::toQStringU(torrent_handle::name());
#else
name = misc::toQStringU(status(query_name).name);
#endif
}
return name;
}
QString QTorrentHandle::creation_date() const
{
#if LIBTORRENT_VERSION_NUM < 10000
boost::optional<time_t> t = torrent_handle::get_torrent_info().creation_date();
#else
boost::optional<time_t> t = torrent_handle::torrent_file()->creation_date();
#endif
return t ? misc::toQString(*t) : "";
}
qlonglong QTorrentHandle::creation_date_unix() const
{
#if LIBTORRENT_VERSION_NUM < 10000
boost::optional<time_t> t = torrent_handle::get_torrent_info().creation_date();
#else
boost::optional<time_t> t = torrent_handle::torrent_file()->creation_date();
#endif
return t ? *t : -1;
}
QString QTorrentHandle::current_tracker() const
{
return misc::toQString(status(0x0).current_tracker);
}
bool QTorrentHandle::is_paused() const
{
return is_paused(status(0x0));
}
bool QTorrentHandle::is_queued() const
{
return is_queued(status(0x0));
}
size_type QTorrentHandle::total_size() const
{
#if LIBTORRENT_VERSION_NUM < 10000
return torrent_handle::get_torrent_info().total_size();
#else
return torrent_handle::torrent_file()->total_size();
#endif
}
size_type QTorrentHandle::piece_length() const
{
#if LIBTORRENT_VERSION_NUM < 10000
return torrent_handle::get_torrent_info().piece_length();
#else
return torrent_handle::torrent_file()->piece_length();
#endif
}
int QTorrentHandle::num_pieces() const
{
#if LIBTORRENT_VERSION_NUM < 10000
return torrent_handle::get_torrent_info().num_pieces();
#else
return torrent_handle::torrent_file()->num_pieces();
#endif
}
bool QTorrentHandle::first_last_piece_first() const
{
#if LIBTORRENT_VERSION_NUM < 10000
torrent_info const* t = &get_torrent_info();
#else
boost::intrusive_ptr<torrent_info const> t = torrent_file();
#endif
// Get int first media file
int index = 0;
for (index = 0; index < t->num_files(); ++index) {
QString path = misc::toQStringU(t->file_at(index).path);
const QString ext = fsutils::fileExtension(path);
if (misc::isPreviewable(ext) && torrent_handle::file_priority(index) > 0)
break;
}
if (index >= t->num_files()) // No media file
return false;
QPair<int, int> extremities = get_file_extremity_pieces(*t, index);
return (torrent_handle::piece_priority(extremities.first) == 7)
&& (torrent_handle::piece_priority(extremities.second) == 7);
}
QString QTorrentHandle::save_path() const
{
#if LIBTORRENT_VERSION_NUM < 10000
return fsutils::fromNativePath(misc::toQStringU(torrent_handle::save_path()));
#else
return fsutils::fromNativePath(misc::toQStringU(status(torrent_handle::query_save_path).save_path));
#endif
}
QString QTorrentHandle::save_path_parsed() const
{
QString p;
if (has_metadata() && num_files() == 1) {
p = firstFileSavePath();
}
else {
p = fsutils::fromNativePath(TorrentPersistentData::instance()->getSavePath(hash()));
if (p.isEmpty())
p = save_path();
}
return p;
}
QStringList QTorrentHandle::url_seeds() const
{
QStringList res;
try {
const std::set<std::string> existing_seeds = torrent_handle::url_seeds();
std::set<std::string>::const_iterator it = existing_seeds.begin();
std::set<std::string>::const_iterator itend = existing_seeds.end();
for (; it != itend; ++it) {
qDebug("URL Seed: %s", it->c_str());
res << misc::toQString(*it);
}
} catch(std::exception &e) {
std::cout << "ERROR: Failed to convert the URL seed" << std::endl;
}
return res;
}
// get the size of the torrent without the filtered files
size_type QTorrentHandle::actual_size() const
{
return status(query_accurate_download_counters).total_wanted;
}
bool QTorrentHandle::has_filtered_pieces() const
{
const std::vector<int> piece_priorities = torrent_handle::piece_priorities();
foreach (const int priority, piece_priorities)
if (priority == 0)
return true;
return false;
}
int QTorrentHandle::num_files() const
{
if (!has_metadata())
return -1;
#if LIBTORRENT_VERSION_NUM < 10000
return torrent_handle::get_torrent_info().num_files();
#else
return torrent_handle::torrent_file()->num_files();
#endif
}
QString QTorrentHandle::filename_at(unsigned int index) const
{
#if LIBTORRENT_VERSION_NUM < 10000
Q_ASSERT(index < (unsigned int)torrent_handle::get_torrent_info().num_files());
#else
Q_ASSERT(index < (unsigned int)torrent_handle::torrent_file()->num_files());
#endif
return fsutils::fileName(filepath_at(index));
}
size_type QTorrentHandle::filesize_at(unsigned int index) const
{
#if LIBTORRENT_VERSION_NUM < 10000
Q_ASSERT(index < (unsigned int)torrent_handle::get_torrent_info().num_files());
return torrent_handle::get_torrent_info().files().file_size(index);
#else
Q_ASSERT(index < (unsigned int)torrent_handle::torrent_file()->num_files());
return torrent_handle::torrent_file()->files().file_size(index);
#endif
}
QString QTorrentHandle::filepath_at(unsigned int index) const
{
#if LIBTORRENT_VERSION_NUM < 10000
return filepath_at(torrent_handle::get_torrent_info(), index);
#else
return filepath_at(*torrent_handle::torrent_file(), index);
#endif
}
QString QTorrentHandle::orig_filepath_at(unsigned int index) const
{
#if LIBTORRENT_VERSION_NUM < 10000
return fsutils::fromNativePath(misc::toQStringU(torrent_handle::get_torrent_info().orig_files().file_path(index)));
#else
return fsutils::fromNativePath(misc::toQStringU(torrent_handle::torrent_file()->orig_files().file_path(index)));
#endif
}
torrent_status::state_t QTorrentHandle::state() const
{
return status(0x0).state;
}
QString QTorrentHandle::creator() const
{
#if LIBTORRENT_VERSION_NUM < 10000
return misc::toQStringU(torrent_handle::get_torrent_info().creator());
#else
return misc::toQStringU(torrent_handle::torrent_file()->creator());
#endif
}
QString QTorrentHandle::comment() const
{
#if LIBTORRENT_VERSION_NUM < 10000
return misc::toQStringU(torrent_handle::get_torrent_info().comment());
#else
return misc::toQStringU(torrent_handle::torrent_file()->comment());
#endif
}
bool QTorrentHandle::is_checking() const
{
return is_checking(status(0x0));
}
// Return a list of absolute paths corresponding
// to all files in a torrent
QStringList QTorrentHandle::absolute_files_path() const
{
QDir saveDir(save_path());
QStringList res;
for (int i = 0; i<num_files(); ++i)
res << fsutils::expandPathAbs(saveDir.absoluteFilePath(filepath_at(i)));
return res;
}
QStringList QTorrentHandle::absolute_files_path_uneeded() const
{
QDir saveDir(save_path());
QStringList res;
std::vector<int> fp = torrent_handle::file_priorities();
for (uint i = 0; i < fp.size(); ++i) {
if (fp[i] == 0) {
const QString file_path = fsutils::expandPathAbs(saveDir.absoluteFilePath(filepath_at(i)));
if (file_path.contains(".unwanted"))
res << file_path;
}
}
return res;
}
bool QTorrentHandle::has_missing_files() const
{
const QStringList paths = absolute_files_path();
foreach (const QString &path, paths)
if (!QFile::exists(path)) return true;
return false;
}
int QTorrentHandle::queue_position() const
{
return queue_position(status(0x0));
}
bool QTorrentHandle::is_seed() const
{
// Affected by bug http://code.rasterbar.com/libtorrent/ticket/402
//return torrent_handle::is_seed();
// May suffer from approximation problems
//return (progress() == 1.);
// This looks safe
return is_seed(status(0x0));
}
bool QTorrentHandle::is_sequential_download() const
{
return status(0x0).sequential_download;
}
bool QTorrentHandle::priv() const
{
if (!has_metadata())
return false;
#if LIBTORRENT_VERSION_NUM < 10000
return torrent_handle::get_torrent_info().priv();
#else
return torrent_handle::torrent_file()->priv();
#endif
}
QString QTorrentHandle::firstFileSavePath() const
{
Q_ASSERT(has_metadata());
QString fsave_path = fsutils::fromNativePath(TorrentPersistentData::instance()->getSavePath(hash()));
if (fsave_path.isEmpty())
fsave_path = save_path();
if (!fsave_path.endsWith("/"))
fsave_path += "/";
fsave_path += filepath_at(0);
// Remove .!qB extension
if (fsave_path.endsWith(".!qB", Qt::CaseInsensitive))
fsave_path.chop(4);
return fsave_path;
}
QString QTorrentHandle::root_path() const
{
if (num_files() < 2)
return save_path();
QString first_filepath = filepath_at(0);
const int slashIndex = first_filepath.indexOf("/");
if (slashIndex >= 0)
return QDir(save_path()).absoluteFilePath(first_filepath.left(slashIndex));
return save_path();
}
bool QTorrentHandle::has_error() const
{
return has_error(status(0x0));
}
QString QTorrentHandle::error() const
{
return misc::toQString(status(0x0).error);
}
void QTorrentHandle::downloading_pieces(bitfield &bf) const
{
std::vector<partial_piece_info> queue;
torrent_handle::get_download_queue(queue);
std::vector<partial_piece_info>::const_iterator it = queue.begin();
std::vector<partial_piece_info>::const_iterator itend = queue.end();
for (; it!= itend; ++it)
bf.set_bit(it->piece_index);
return;
}
bool QTorrentHandle::has_metadata() const
{
return status(0x0).has_metadata;
}
void QTorrentHandle::file_progress(std::vector<size_type>& fp) const
{
torrent_handle::file_progress(fp, torrent_handle::piece_granularity);
}
QTorrentState QTorrentHandle::torrentState() const
{
QTorrentState state = QTorrentState::Unknown;
libtorrent::torrent_status s = status(torrent_handle::query_accurate_download_counters);
if (is_paused(s)) {
if (has_error(s))
state = QTorrentState::Error;
else
state = is_seed(s) ? QTorrentState::PausedUploading : QTorrentState::PausedDownloading;
}
else {
if (QBtSession::instance()->isQueueingEnabled() && is_queued(s)) {
state = is_seed(s) ? QTorrentState::QueuedUploading : QTorrentState::QueuedDownloading;
}
else {
switch (s.state) {
case torrent_status::finished:
case torrent_status::seeding:
state = s.upload_payload_rate > 0 ? QTorrentState::Uploading : QTorrentState::StalledUploading;
break;
case torrent_status::allocating:
case torrent_status::checking_files:
case torrent_status::queued_for_checking:
case torrent_status::checking_resume_data:
state = is_seed(s) ? QTorrentState::CheckingUploading : QTorrentState::CheckingDownloading;
break;
case torrent_status::downloading:
case torrent_status::downloading_metadata:
state = s.download_payload_rate > 0 ? QTorrentState::Downloading : QTorrentState::StalledDownloading;
break;
default:
qWarning("Unrecognized torrent status, should not happen!!! status was %d", this->state());
}
}
}
return state;
}
qulonglong QTorrentHandle::eta() const
{
libtorrent::torrent_status s = status(torrent_handle::query_accurate_download_counters);
return QBtSession::instance()->getETA(hash(), s);
}
void QTorrentHandle::toggleSequentialDownload()
{
if (is_valid() && has_metadata()) {
bool was_sequential = is_sequential_download();
set_sequential_download(!was_sequential);
if (!was_sequential)
prioritize_first_last_piece(true);
}
}
void QTorrentHandle::toggleFirstLastPiecePrio()
{
if (is_valid() && has_metadata())
prioritize_first_last_piece(!first_last_piece_first());
}
bool QTorrentHandle::is_forced() const
{
return is_forced(status(0x0));
}
//
// Setters
//
void QTorrentHandle::pause() const
{
torrent_handle::auto_managed(false);
torrent_handle::pause();
if (!TorrentPersistentData::instance()->getHasMissingFiles(this->hash()))
torrent_handle::save_resume_data();
}
void QTorrentHandle::resume(const bool force) const
{
if (has_error())
torrent_handle::clear_error();
torrent_handle::set_upload_mode(false);
const QString torrent_hash = hash();
TorrentPersistentData* const TorPersistent = TorrentPersistentData::instance();
bool has_persistant_error = TorPersistent->hasError(torrent_hash);
TorPersistent->setErrorState(torrent_hash, false);
bool temp_path_enabled = Preferences::instance()->isTempPathEnabled();
TorPersistent->setHasMissingFiles(torrent_hash, false);
if (has_persistant_error && temp_path_enabled) {
// Torrent was supposed to be seeding, checking again in final destination
qDebug("Resuming a torrent with error...");
const QString final_save_path = TorPersistent->getSavePath(torrent_hash);
qDebug("Torrent final path is: %s", qPrintable(final_save_path));
if (!final_save_path.isEmpty())
move_storage(final_save_path);
}
torrent_handle::auto_managed(!force);
torrent_handle::resume();
if (has_persistant_error && temp_path_enabled)
// Force recheck
torrent_handle::force_recheck();
}
void QTorrentHandle::remove_url_seed(const QString& seed) const
{
torrent_handle::remove_url_seed(seed.toStdString());
}
void QTorrentHandle::add_url_seed(const QString& seed) const
{
const std::string str_seed = seed.toStdString();
qDebug("calling torrent_handle::add_url_seed(%s)", str_seed.c_str());
torrent_handle::add_url_seed(str_seed);
}
void QTorrentHandle::set_tracker_login(const QString& username, const QString& password) const
{
torrent_handle::set_tracker_login(std::string(username.toLocal8Bit().constData()), std::string(password.toLocal8Bit().constData()));
}
void QTorrentHandle::move_storage(const QString& new_path) const
{
QString hashstr = hash();
if (TorrentTempData::isMoveInProgress(hashstr)) {
qDebug("enqueue move storage to %s", qPrintable(new_path));
TorrentTempData::enqueueMove(hashstr, new_path);
}
else {
QString old_path = save_path();
qDebug("move storage: %s to %s", qPrintable(old_path), qPrintable(new_path));
if (QDir(old_path) == QDir(new_path))
return;
TorrentTempData::startMove(hashstr, old_path, new_path);
// Create destination directory if necessary
// or move_storage() will fail...
QDir().mkpath(new_path);
// Actually move the storage
torrent_handle::move_storage(fsutils::toNativePath(new_path).toUtf8().constData());
}
}
bool QTorrentHandle::save_torrent_file(const QString& path) const
{
if (!has_metadata()) return false;
#if LIBTORRENT_VERSION_NUM < 10000
torrent_info const* t = &get_torrent_info();
#else
boost::intrusive_ptr<torrent_info const> t = torrent_file();
#endif
entry meta = bdecode(t->metadata().get(),
t->metadata().get() + t->metadata_size());
entry torrent_entry(entry::dictionary_t);
torrent_entry["info"] = meta;
if (!torrent_handle::trackers().empty())
torrent_entry["announce"] = torrent_handle::trackers().front().url;
vector<char> out;
bencode(back_inserter(out), torrent_entry);
QFile torrent_file(path);
if (!out.empty() && torrent_file.open(QIODevice::WriteOnly)) {
torrent_file.write(&out[0], out.size());
torrent_file.close();
return true;
}
return false;
}
void QTorrentHandle::file_priority(int index, int priority) const
{
vector<int> priorities = torrent_handle::file_priorities();
if (priorities[index] != priority) {
priorities[index] = priority;
prioritize_files(priorities);
}
}
void QTorrentHandle::prioritize_files(const vector<int> &files) const
{
#if LIBTORRENT_VERSION_NUM < 10000
torrent_info const& info = torrent_handle::get_torrent_info();
#else
boost::intrusive_ptr<torrent_info const> info_ptr = torrent_handle::torrent_file();
torrent_info const& info = *info_ptr;
#endif
if ((int)files.size() != info.num_files()) return;
qDebug() << Q_FUNC_INFO;
bool was_seed = is_seed();
qDebug() << Q_FUNC_INFO << "Changing files priorities...";
torrent_handle::prioritize_files(files);
qDebug() << Q_FUNC_INFO << "Moving unwanted files to .unwanted folder and conversely...";
QString spath = save_path();
for (uint i = 0; i < files.size(); ++i) {
QString filepath = filepath_at(info, i);
// Move unwanted files to a .unwanted subfolder
if (files[i] == 0) {
QString old_abspath = QDir(spath).absoluteFilePath(filepath);
QString parent_abspath = fsutils::branchPath(old_abspath);
// Make sure the file does not already exists
if (QDir(parent_abspath).dirName() != ".unwanted") {
QString unwanted_abspath = parent_abspath + "/.unwanted";
QString new_abspath = unwanted_abspath + "/" + fsutils::fileName(filepath);
qDebug() << "Unwanted path is" << unwanted_abspath;
if (QFile::exists(new_abspath)) {
qWarning() << "File" << new_abspath << "already exists at destination.";
continue;
}
bool created = QDir().mkpath(unwanted_abspath);
#ifdef Q_OS_WIN
qDebug() << "unwanted folder was created:" << created;
if (created) {
// Hide the folder on Windows
qDebug() << "Hiding folder (Windows)";
wstring win_path = fsutils::toNativePath(unwanted_abspath).toStdWString();
DWORD dwAttrs = GetFileAttributesW(win_path.c_str());
bool ret = SetFileAttributesW(win_path.c_str(), dwAttrs | FILE_ATTRIBUTE_HIDDEN);
Q_ASSERT(ret != 0); Q_UNUSED(ret);
}
#else
Q_UNUSED(created);
#endif
QString parent_path = fsutils::branchPath(filepath);
if (!parent_path.isEmpty() && !parent_path.endsWith("/"))
parent_path += "/";
rename_file(i, parent_path + ".unwanted/" + fsutils::fileName(filepath));
}
}
// Move wanted files back to their original folder
if (files[i] > 0) {
QString parent_relpath = fsutils::branchPath(filepath);
if (QDir(parent_relpath).dirName() == ".unwanted") {
QString old_name = fsutils::fileName(filepath);
QString new_relpath = fsutils::branchPath(parent_relpath);
if (new_relpath.isEmpty())
rename_file(i, old_name);
else
rename_file(i, QDir(new_relpath).filePath(old_name));
// Remove .unwanted directory if empty
qDebug() << "Attempting to remove .unwanted folder at " << QDir(spath + "/" + new_relpath).absoluteFilePath(".unwanted");
QDir(spath + "/" + new_relpath).rmdir(".unwanted");
}
}
}
if (was_seed && !is_seed()) {
qDebug() << "Torrent is no longer SEEDING";
// Save seed status
TorrentPersistentData::instance()->saveSeedStatus(*this);
// Move to temp folder if necessary
const Preferences* const pref = Preferences::instance();
if (pref->isTempPathEnabled()) {
QString tmp_path = pref->getTempPath();
qDebug() << "tmp folder is enabled, move torrent to " << tmp_path << " from " << spath;
move_storage(tmp_path);
}
}
}
void QTorrentHandle::prioritize_first_last_piece(int file_index, bool b) const
{
// Determine the priority to set
int prio = b ? 7 : torrent_handle::file_priority(file_index);
#if LIBTORRENT_VERSION_NUM < 10000
torrent_info const* tf = &get_torrent_info();
#else
boost::intrusive_ptr<torrent_info const> tf = torrent_file();
#endif
QPair<int, int> extremities = get_file_extremity_pieces(*tf, file_index);
piece_priority(extremities.first, prio);
piece_priority(extremities.second, prio);
}
void QTorrentHandle::prioritize_first_last_piece(bool b) const
{
if (!has_metadata()) return;
// Download first and last pieces first for all media files in the torrent
const int nbfiles = num_files();
for (int index = 0; index < nbfiles; ++index) {
const QString path = filepath_at(index);
const QString ext = fsutils::fileExtension(path);
if (misc::isPreviewable(ext) && torrent_handle::file_priority(index) > 0) {
qDebug() << "File" << path << "is previewable, toggle downloading of first/last pieces first";
prioritize_first_last_piece(index, b);
}
}
}
void QTorrentHandle::rename_file(int index, const QString& name) const
{
qDebug() << Q_FUNC_INFO << index << name;
torrent_handle::rename_file(index, std::string(fsutils::toNativePath(name).toUtf8().constData()));
}
//
// Operators
//
bool QTorrentHandle::operator ==(const QTorrentHandle& new_h) const
{
return info_hash() == new_h.info_hash();
}
bool QTorrentHandle::is_paused(const libtorrent::torrent_status &status)
{
return status.paused && !status.auto_managed;
}
int QTorrentHandle::queue_position(const libtorrent::torrent_status &status)
{
if (status.queue_position < 0)
return -1;
return status.queue_position + 1;
}
bool QTorrentHandle::is_queued(const libtorrent::torrent_status &status)
{
return status.paused && status.auto_managed;
}
bool QTorrentHandle::is_seed(const libtorrent::torrent_status &status)
{
return status.state == torrent_status::finished
|| status.state == torrent_status::seeding;
}
bool QTorrentHandle::is_checking(const libtorrent::torrent_status &status)
{
return status.state == torrent_status::checking_files
|| status.state == torrent_status::checking_resume_data;
}
bool QTorrentHandle::has_error(const libtorrent::torrent_status &status)
{
return status.paused && !status.error.empty();
}
float QTorrentHandle::progress(const libtorrent::torrent_status &status)
{
if (!status.total_wanted)
return 0.;
if (status.total_wanted_done == status.total_wanted)
return 1.;
float progress = (float) status.total_wanted_done / (float) status.total_wanted;
Q_ASSERT(progress >= 0.f && progress <= 1.f);
return progress;
}
QString QTorrentHandle::filepath_at(const libtorrent::torrent_info &info, unsigned int index)
{
return fsutils::fromNativePath(misc::toQStringU(info.files().file_path(index)));
}
bool QTorrentHandle::is_forced(const libtorrent::torrent_status &status)
{
return !status.paused && !status.auto_managed;
}
QTorrentState::QTorrentState(int value)
: m_value(value)
{
}
QString QTorrentState::toString() const
{
switch (m_value) {
case Error:
return "error";
case Uploading:
return "uploading";
case PausedUploading:
return "pausedUP";
case QueuedUploading:
return "queuedUP";
case StalledUploading:
return "stalledUP";
case CheckingUploading:
return "checkingUP";
case Downloading:
return "downloading";
case PausedDownloading:
return "pausedDL";
case QueuedDownloading:
return "queuedDL";
case StalledDownloading:
return "stalledDL";
case CheckingDownloading:
return "checkingDL";
default:
return "unknown";
}
}
QTorrentState::operator int() const
{
return m_value;
}

View File

@@ -1,170 +0,0 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* 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
* 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.
*
* Contact : chris@qbittorrent.org
*/
#ifndef QTORRENTHANDLE_H
#define QTORRENTHANDLE_H
#include <libtorrent/torrent_handle.hpp>
#include <QString>
QT_BEGIN_NAMESPACE
class QStringList;
QT_END_NAMESPACE
class QTorrentState
{
public:
enum
{
Unknown = -1,
Error,
Uploading,
PausedUploading,
QueuedUploading,
StalledUploading,
CheckingUploading,
Downloading,
PausedDownloading,
QueuedDownloading,
StalledDownloading,
CheckingDownloading
};
QTorrentState(int value);
operator int() const;
QString toString() const;
private:
int m_value;
};
// A wrapper for torrent_handle in libtorrent
// to interact well with Qt types
class QTorrentHandle: public libtorrent::torrent_handle
{
public:
//
// Constructors
//
QTorrentHandle() {}
explicit QTorrentHandle(const libtorrent::torrent_handle& h);
//
// Getters
//
QString hash() const;
QString name() const;
QString current_tracker() const;
bool is_paused() const;
bool has_filtered_pieces() const;
libtorrent::size_type total_size() const;
libtorrent::size_type piece_length() const;
int num_pieces() const;
QString save_path() const;
QString save_path_parsed() const;
QStringList url_seeds() const;
libtorrent::size_type actual_size() const;
int num_files() const;
int queue_position() const;
bool is_queued() const;
QString filename_at(unsigned int index) const;
libtorrent::size_type filesize_at(unsigned int index) const;
QString filepath_at(unsigned int index) const;
QString orig_filepath_at(unsigned int index) const;
libtorrent::torrent_status::state_t state() const;
QString creator() const;
QString comment() const;
QStringList absolute_files_path() const;
QStringList absolute_files_path_uneeded() const;
bool has_missing_files() const;
bool is_seed() const;
bool is_checking() const;
bool is_sequential_download() const;
QString creation_date() const;
qlonglong creation_date_unix() const;
bool priv() const;
bool first_last_piece_first() const;
QString root_path() const;
QString firstFileSavePath() const;
bool has_error() const;
QString error() const;
void downloading_pieces(libtorrent::bitfield& bf) const;
bool has_metadata() const;
void file_progress(std::vector<libtorrent::size_type>& fp) const;
QTorrentState torrentState() const;
qulonglong eta() const;
void toggleSequentialDownload();
void toggleFirstLastPiecePrio();
bool is_forced() const;
//
// Setters
//
void pause() const;
void resume(const bool force = false) const;
void remove_url_seed(const QString& seed) const;
void add_url_seed(const QString& seed) const;
void set_tracker_login(const QString& username, const QString& password) const;
void move_storage(const QString& path) const;
void prioritize_first_last_piece(bool b) const;
void rename_file(int index, const QString& name) const;
bool save_torrent_file(const QString& path) const;
void prioritize_files(const std::vector<int>& files) const;
void file_priority(int index, int priority) const;
//
// Operators
//
bool operator ==(const QTorrentHandle& new_h) const;
static bool is_paused(const libtorrent::torrent_status &status);
static int queue_position(const libtorrent::torrent_status &status);
static bool is_queued(const libtorrent::torrent_status &status);
static bool is_seed(const libtorrent::torrent_status &status);
static bool is_checking(const libtorrent::torrent_status &status);
static bool has_error(const libtorrent::torrent_status &status);
static float progress(const libtorrent::torrent_status &status);
static QString filepath_at(const libtorrent::torrent_info &info, unsigned int index);
static bool is_forced(const libtorrent::torrent_status &status);
private:
void prioritize_first_last_piece(int file_index, bool b) const;
};
#endif

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