Compare commits

..

2 Commits

Author SHA1 Message Date
sledgehammer999
52f8f9beb4 Bump to 3.2.0 2015-05-10 04:20:19 +03:00
sledgehammer999
3f110dabed Update Transifex config file. 2015-05-10 04:20:06 +03:00
412 changed files with 116781 additions and 237242 deletions

9
.gitignore vendored
View File

@@ -2,19 +2,13 @@ src/gui/geoip/GeoIP.dat
src/gui/geoip/GeoIP.dat.gz
src/qbittorrent
src/qbittorrent-nox
src/release
src/debug
qbittorrent.pro.user*
conf.pri
Makefile*
Makefile
*.pyc
*.log
# Compiled object files
*.o
*.pdb
*.exe
# Generated MOC, resource and UI files
moc_*.cpp
qrc_*.cpp
@@ -25,7 +19,6 @@ src/lang/qbittorrent_*.qm
.qmake.stash
src/qbittorrent.app
*.dmg
#Autotools junk
aclocal.m4
autom4te.cache/*

View File

@@ -1,29 +1,16 @@
language: cpp
os:
- linux
- osx
osx_image: xcode7
language:
- cpp
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_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
# use libtorrent 0.15.10
# uncomment when Travis doesn't use Ubuntu 12.04 LTS, which has libtorrent 0.15.10 as package
#- lt_source=from_dist gui=true
#- lt_source=from_dist gui=false
# use libtorrent 0.16.X from RC_0_16 svn branch
- lt_source=from_svnRC_0_16 gui=true
- lt_source=from_svnRC_0_16 gui=false
- lt_source=from_svnRC_1_0 gui=true
- lt_source=from_svnRC_1_0 gui=false
branches:
except:
@@ -33,89 +20,41 @@ branches:
notifications:
email:
on_success: change
on_failure: change
# 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
addons:
coverity_scan:
project:
name: "qbittorrent/qBittorrent"
description: "Build submitted via Travis CI"
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
- 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
on_failure: change
before_install:
# Only allow specific build for coverity scan, others will stop
- if [ "$TRAVIS_BRANCH" = "$coverity_branch" ] && ! [ "$TRAVIS_OS_NAME" = "linux" -a "$lt_branch" = "RC_1_0" -a "$gui" = true ]; then exit ; fi
- shopt -s expand_aliases
- 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)
- alias sudo="sudo "
# Using nprocs/2 sometimes may fail (gcc is killed by system), just use two threads
- alias make="colormake -j2 "
- libt_path="$HOME/libt_install"
- qbt_path="$HOME/qbt_install"
- 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
# Also setup a virtual display for after_success target when gui == true
- 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
- 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
- qbtconf="$qbtconf --with-qt4"
- ltconf=" --with-libgeoip=system"
# Print settings
- echo $lt_branch
- echo $gui
- echo settings
- echo $lt_source
- echo $ltconf
- echo $gui
- echo $qbtconf
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then ccache -V && ccache --show-stats && ccache --zero-stats ; fi
- sudo apt-get -qq update
# Travis can stall during heavy load if these packages are installed in one step - split the command
- sudo apt-get -qq install debhelper autoconf automake colormake libssl-dev libgeoip-dev
# uncomment when Travis doesn't use Ubuntu 12.04 LTS, which has libtorrent 0.15.10 as package
#- sudo apt-get -qq install libboost-dev libboost-filesystem-dev libboost-system-dev
- sudo apt-get -qq install libboost-dev libboost-system-dev
- sudo apt-get -qq install libqt4-dev
install:
- 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
#- if [[ "$lt_source" == "from_dist" ]]; then sudo apt-get -qq install libtorrent-rasterbar-dev; fi
- if [[ "$lt_source" == "from_svnRC_0_16" ]]; then qbtconf="$qbtconf --with-libtorrent-rasterbar0.16" && cd .. && svn co svn://svn.code.sf.net/p/libtorrent/code/branches/RC_0_16 ./libtorrent && (cd libtorrent && ./autotool.sh && ./configure $ltconf && sudo make install) && sudo ldconfig /usr/local/lib && cd $TRAVIS_BUILD_DIR ; fi
- if [[ "$lt_source" == "from_svnRC_1_0" ]]; then cd .. && svn co svn://svn.code.sf.net/p/libtorrent/code/branches/RC_1_0 ./libtorrent && (cd libtorrent && ./autotool.sh && ./configure $ltconf && sudo make install) && sudo ldconfig /usr/local/lib && cd $TRAVIS_BUILD_DIR ; fi
script:
- if [ "$TRAVIS_BRANCH" = "$coverity_branch" ]; then exit ; fi # Skip usual build when running coverity scan
- ./bootstrap.sh && ./configure $qbtconf
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then echo QMAKE_CC=$CC >> conf.pri && echo QMAKE_CXX=$CXX >> conf.pri ; fi
- make && make install
- ./bootstrap.sh
- ./configure $qbtconf && sudo make install
after_success:
- 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:
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then ccache --show-stats ; fi
- if $gui ; then qbittorrent --version ; else qbittorrent-nox --version ; fi

View File

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

View File

@@ -10,20 +10,18 @@ int myFunction(int a)
//code
}
void myFunction() {} // empty body
MyClass::MyClass(int *parent)
myClass::myClass(int *parent)
: m_parent(parent)
{
//initialize
//initialiaze
}
int MyClass::myMethod(int a)
int myClass::myMethod(int a)
{
//code
}
class MyOtherClass
class myOtherClass
{
public:
//code
@@ -33,18 +31,10 @@ private:
//code
};
namespace Name
namespace id
{
//code
}
// Lambdas
[](int arg1, int arg2) -> bool { return arg1 < arg2; }
[this](int arg)
{
this->acc += arg;
}
```
#### b. Other code blocks ####
@@ -85,12 +75,6 @@ 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++
@@ -135,16 +119,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 specific files need other encodings/line endings.
UTF-8 and Unix-like line ending (LF). Unless some platform speficic files need other encodings/line endings.
### 5. Initialization lists.###
Initialization lists should be vertical. This will allow for more easily readable diffs. The initialization colon should be indented and in its own line along with first argument. The rest of the arguments should be indented too and have the comma prepended.
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.
```c++
myClass::myClass(int a, int b, int c, int d)
: m_a(a)
, m_b(b)
, m_c(c)
, m_d(d)
: priv_a(a)
, priv_b(b)
, priv_c(c)
, priv_d(d)
{
//code
}
@@ -153,7 +137,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,
@@ -165,41 +149,7 @@ enum Days
};
```
### 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.###
### 7. Misc.###
* Line breaks for long lines with operation:

View File

@@ -1,36 +0,0 @@
# Filing an issue
### Must read
* If you aren't sure, you can ask on the [**forum**](http://forum.qbittorrent.org) or read our [**wiki**](http://wiki.qbittorrent.org) first.
* Do a quick **search**. Others might already reported the issue.
* Write in **English**!
* Provide **version** information: (You can find version numbers at menu `Help -> About -> Libraries`)
```
qBittorrent:
Qt:
libtorrent:
boost:
OS version:
```
* Provide **steps** to reproduce the problem, it will be easier to pinpoint the fault.
* **Screenshots**! A screenshot is worth a thousand words. just upload it. [(How?)](https://help.github.com/articles/file-attachments-on-issues-and-pull-requests)
### Good to know
* **Patience**. The dev team is small and resource limited. Devs finding their free time, analyzing the problem and fixing the issue, it all takes time. :clock3:
* If you can code, why not become a **contributor** by fixing the issue and open a pull request? :wink:
* Harsh words or threats won't help your situation. What's worse, your complain will (very likely) to be **ignored**. :fearful:
# Opening a pull request
### Must read
* Read our [**coding guidelines**](https://github.com/qbittorrent/qBittorrent/blob/master/CODING_GUIDELINES.md). There are some scripts to help you: [uncrustify script](https://gist.github.com/sledgehammer999/1cb1d9224d7fec8fa632), [astyle script](https://gist.github.com/Chocobo1/539cee860d1eef0acfa6), [(related thread)](https://github.com/qbittorrent/qBittorrent/issues/2192).
* Keep the title **short** and provide a **clear** description about what your pull request does.
* Provide **screenshots** for UI related changes.
* Keep your git commit history **clean** and **precise**. Commits like `xxx fixup` should not appear.
* If your commit fix a reported issue (for example #4134), add the following message to the commit `Closes #4134.`. Example [here](https://github.com/qbittorrent/qBittorrent/commit/a74bac20c4e8de9776bf9bb77fdc7526135d1988).
### Good to know
* **Search** pull request history! Others might already implemented your idea and is waiting to be merged (or got rejected already). Save your precious time by doing a search first.
* When resolving merge conflicts, do `git rebase <target_branch_name>`, don't do `git pull`. Then you can start fixing the conflicts. Here is a good explanation: [link](https://www.atlassian.com/git/tutorials/merging-vs-rebasing).

View File

@@ -1,79 +1,3 @@
* Tue Dec 08 2015 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.3.1
- FEATURE: New "Set as default label" option in Add torrent dialog. (takiz)
- FEATURE: Support wildcards for filtering torrent list and torrent content (vlakoff)
- BUGFIX: Fix -1 is displayed instead of the infinity symbol (Chocobo1)
- BUGFIX: Fix scan dirs settings saving. Closes #4254, #4239, #4187. (glassez)
- BUGFIX: Exported torrents now use name instead of hash. Closes #4205. (glassez)
- BUGFIX: Improve upgrade to v3.3.0. Now undownloaded magnets will be migrated too. Fixes #4195. (glassez)
- BUGFIX: Fix wrong encoding for listen failed error message. (glassez)
- BUGFIX: Fix RSS not automarking articles as read. (glassez)
- BUGFIX: Fix possible deadlock during application exit. (sledgehammer999)
- WEBUI: Cookies support on WebUI when downloading torrent from a URL. (Naikel Aparicio)
- WEBUI: Modified download and upload windows to allow autocompletion of browsers. (Naikel Aparicio)
- WEBUI: Fixed the spinner in the WebUI upload page. (Naikel Aparicio)
- WEBUI: Modified height of the WebUI download page. (Naikel Aparicio)
- WEBUI: Fixed all the JavaScript functions for download and upload pages. (Naikel Aparicio)
- WEBUI: Add seeds tab to WebUI (buinsky)
- WEBUI: Bump WebUI API_VERSION.
- COSMETIC: Cleanup "Trackers", "Peers", "HTTP Sources", "Speed" and "Content" page layout (Chocobo1)
- COSMETIC: Reduce mainwindow border width (Chocobo1)
- COSMETIC: Use QLineEdit built-in ClearButton (Qt5 only) (Chocobo1)
- COSMETIC: Change text description for half-open connection (Chocobo1)
- OTHER: Change update URL to FossHub. Closes #4188. (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)
- FEATURE: Support per tracker re-announce. Needs libtorrent v1.0.0 (Gelmir)

10
INSTALL
View File

@@ -14,11 +14,15 @@ qBittorrent - A BitTorrent client in C++ / Qt4
- pkg-config executable
- libtorrent-rasterbar by Arvid Norberg (>= 1.0.6)
- libtorrent-rasterbar by Arvid Norberg (>= 0.15.0)
-> http://www.libtorrent.net
Be careful: another library (the one used by rTorrent) uses a similar name.
- libboost >= 1.35.x (libboost-system)
- 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
- python >= 2.3 (needed by search engine)
* Run time only dependency
@@ -40,7 +44,7 @@ qBittorrent - A BitTorrent client in C++ / Qt4
- pkg-config executable
- libtorrent-rasterbar by Arvid Norberg (>= v1.0.6)
- libtorrent-rasterbar by Arvid Norberg (>= v0.15.0)
-> http://www.libtorrent.net
Be careful: another library (the one used by rTorrent) uses a similar name.

View File

@@ -1,10 +1,9 @@
qBittorrent - A BitTorrent client in Qt
------------------------------------------
[![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)
[![Build Status](https://travis-ci.org/qbittorrent/qBittorrent.png?branch=master)](https://travis-ci.org/qbittorrent/qBittorrent)
********************************
### Description:
###Description:
qBittorrent is a bittorrent client programmed in C++ / Qt that uses
libtorrent (sometimes called libtorrent-rasterbar) by Arvid Norberg.
@@ -32,9 +31,6 @@ 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
@@ -43,3 +39,4 @@ You can also meet me (sledgehammer_999) on IRC:
------------------------------------------
sledgehammer999 <sledgehammer999@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 begin #####
##### conf.pri content beginn #####
BINDIR = ./bin
INCDIR = ./include
LIBDIR = ./lib

618
configure vendored
View File

@@ -601,10 +601,10 @@ EXPAND_BINDIR
EXPAND_PREFIX
zlib_LIBS
zlib_CFLAGS
libtorrent_LIBS
libtorrent_CFLAGS
qjson_LIBS
qjson_CFLAGS
libtorrent_LIBS
libtorrent_CFLAGS
BOOST_SYSTEM_LIB
BOOST_LDFLAGS
BOOST_CPPFLAGS
@@ -690,7 +690,6 @@ infodir
docdir
oldincludedir
includedir
runstatedir
localstatedir
sharedstatedir
sysconfdir
@@ -715,7 +714,9 @@ ac_user_opts='
enable_option_checking
enable_dependency_tracking
enable_silent_rules
with_qt4
with_qt5
with_libtorrent_rasterbar0_16
with_geoip_database_embedded
with_qtsingleapplication
with_qjson
enable_debug
@@ -742,10 +743,10 @@ PKG_CONFIG
PKG_CONFIG_PATH
PKG_CONFIG_LIBDIR
QT_QMAKE
qjson_CFLAGS
qjson_LIBS
libtorrent_CFLAGS
libtorrent_LIBS
qjson_CFLAGS
qjson_LIBS
zlib_CFLAGS
zlib_LIBS'
@@ -786,7 +787,6 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1039,15 +1039,6 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
-runstatedir | --runstatedir | --runstatedi | --runstated \
| --runstate | --runstat | --runsta | --runst | --runs \
| --run | --ru | --r)
ac_prev=runstatedir ;;
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
| --run=* | --ru=* | --r=*)
runstatedir=$ac_optarg ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1185,7 +1176,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
libdir localedir mandir runstatedir
libdir localedir mandir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@@ -1338,7 +1329,6 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@@ -1393,13 +1383,20 @@ Optional Features:
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-qt4 Compile using Qt4 (default=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/geoip/README) (default=no)
--with-qtsingleapplication=[system|shipped]
Use the shipped qtsingleapplication library or the
system one (default=shipped)
--with-qjson=[system|shipped]
Use the shipped qjson library or the system one
(default=shipped) (Qt4 only)
(default=shipped) (Qt4 only
--with-boost[=ARG] use Boost library from a standard location
(ARG=yes), from the specified location (ARG=<path>),
or disable it (ARG=no) [ARG=yes]
@@ -1429,14 +1426,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 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
QT_QMAKE value of moc_location for QtCore >= 4.8.0, 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
@@ -3278,7 +3275,7 @@ IFS=$ac_save_IFS
case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
am__api_version='1.15'
am__api_version='1.14'
# Find a good install program. We prefer a C program (faster),
# so one script is as good as another. But avoid the broken or
@@ -3467,7 +3464,7 @@ else
$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
fi
if test x"${install_sh+set}" != xset; then
if test x"${install_sh}" != xset; then
case $am_aux_dir in
*\ * | *\ *)
install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
@@ -3858,8 +3855,8 @@ MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
mkdir_p='$(MKDIR_P)'
# We need awk for the "check" target (and possibly the TAP driver). The
# system "awk" is bad on some platforms.
# We need awk for the "check" target. The system "awk" is bad on
# some platforms.
# Always define AMTAR for backward compatibility. Yes, it's still used
# in the wild :-( We should find a proper way to deprecate it ...
AMTAR='$${TAR-tar}'
@@ -4179,11 +4176,29 @@ fi
# Define --wth-* and --enable-* arguments
# Check whether --with-qt4 was given.
if test "${with_qt4+set}" = set; then :
withval=$with_qt4;
# Check whether --with-qt5 was given.
if test "${with_qt5+set}" = set; then :
withval=$with_qt5;
else
with_qt4=no
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
fi
@@ -4248,7 +4263,7 @@ fi
# Detect OS
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OS is FreeBSD" >&5
$as_echo_n "checking whether OS is FreeBSD... " >&6; }
if expr "$host_os" : ".*freebsd.*" > /dev/null; then :
if test "x$host_os" = "x*FreeBSD*"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
LIBS="-lexecinfo $LIBS"
@@ -4414,6 +4429,7 @@ $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
@@ -4455,106 +4471,13 @@ $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 Qt4 should be enabled" >&5
$as_echo_n "checking whether Qt4 should be enabled... " >&6; }
case "x$with_qt4" in #(
{ $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 #(
"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=$?
@@ -4666,12 +4589,105 @@ 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_qt4" >&5
$as_echo "$with_qt4" >&6; }
as_fn_error $? "Unknown option \"$with_qt4\". Use either \"yes\" or \"no\"." "$LINENO" 5 ;;
{ $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 ;;
esac
if test "x$QT_QMAKE" = "x"; then :
as_fn_error $? "Could not find qmake" "$LINENO" 5
@@ -4684,7 +4700,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_qt4" = "xno"; then :
if test "x$with_qt5" = "xyes"; 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" && \
@@ -4795,11 +4811,8 @@ $as_echo_n "checking for boostlib >= $boost_lib_version_req... " >&6; }
libsubdirs="lib"
ax_arch=`uname -m`
case $ax_arch in
x86_64)
libsubdirs="lib64 libx32 lib lib64"
;;
ppc64|s390x|sparc64|aarch64|ppc64le)
libsubdirs="lib64 lib lib64 ppc64le"
x86_64|ppc64|s390x|sparc64|aarch64)
libsubdirs="lib64 lib lib64"
;;
esac
@@ -4890,10 +4903,6 @@ 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
@@ -4906,11 +4915,6 @@ 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
@@ -5290,6 +5294,222 @@ $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-raser 0.16.x" >&5
$as_echo_n "checking whether to compile using libtorrent-raser 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.0\""; } >&5
($PKG_CONFIG --exists --print-errors "libtorrent-rasterbar >= 1.0.0") 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.0" 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.0\""; } >&5
($PKG_CONFIG --exists --print-errors "libtorrent-rasterbar >= 1.0.0") 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.0" 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.0" 2>&1`
else
libtorrent_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libtorrent-rasterbar >= 1.0.0" 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.0) 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.0\""; } >&5
($PKG_CONFIG --exists --print-errors "libtorrent-rasterbar >= 0.16.0") 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.0" 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.0\""; } >&5
($PKG_CONFIG --exists --print-errors "libtorrent-rasterbar >= 0.16.0") 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.0" 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.0" 2>&1`
else
libtorrent_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libtorrent-rasterbar >= 0.16.0" 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.0) 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 #(
@@ -5307,7 +5527,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_qt4" = "xyes"; then :
if test "x$with_qt5" = "xno"; 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 #(
@@ -5420,99 +5640,6 @@ 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; }
@@ -5674,18 +5801,15 @@ _ACEOF
# Original extract() function contributed by pmzqla
# $*: Strings to parse
# Set $QBT_CONF_DEFINES, $QBT_CONF_INCLUDES, $QBT_CONF_EXTRA_CFLAGS
# Set $DEFINES, $INCLUDES, $OTHER
extract() {
if [ -z "$*" ]; then
echo "Input string required"
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: -:\\${new_line}:g" -e 's:"\(.*\)\n\(.*\)":\"\1 -\2":g' -e "s:'\(.*\)\n\(.*\)':\'\1 -\2':g" -e 's/^[:space:]*//')
# Convert " -" to "\n" if not between quotes
string=$(echo " $*" | $SED -e 's: -:\n:g' -e 's:"\(.*\)\n\(.*\)":\"\1 -\2":g' -e "s:'\(.*\)\n\(.*\)':\'\1 -\2':g")
SAVEIFS=$IFS
IFS=$(printf "\n\b")
for i in $string; do

View File

@@ -12,11 +12,23 @@ AM_INIT_AUTOMAKE
# Define --wth-* and --enable-* arguments
AC_ARG_WITH(qt4,
[AS_HELP_STRING([--with-qt4],
[Compile using Qt4 (default=no)])],
AC_ARG_WITH(qt5,
[AS_HELP_STRING([--with-qt5],
[Compile using Qt5 (default=no)])],
[],
[with_qt4=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/geoip/README) (default=no)])],
[],
[with_geoip_database_embedded=no])
AC_ARG_WITH(qtsingleapplication,
[AS_HELP_STRING([--with-qtsingleapplication=@<:@system|shipped@:>@],
@@ -26,7 +38,7 @@ AC_ARG_WITH(qtsingleapplication,
AC_ARG_WITH(qjson,
[AS_HELP_STRING([--with-qjson=@<:@system|shipped@:>@],
[Use the shipped qjson library or the system one (default=shipped) (Qt4 only)])],
[Use the shipped qjson library or the system one (default=shipped) (Qt4 only])],
[],
[with_qjson=shipped])
@@ -62,7 +74,7 @@ AC_ARG_ENABLE(qt-dbus,
# Detect OS
AC_MSG_CHECKING([whether OS is FreeBSD])
AS_IF([expr "$host_os" : ".*freebsd.*" > /dev/null],
AS_IF([test "x$host_os" = "x*FreeBSD*"],
[AC_MSG_RESULT([yes])
LIBS="-lexecinfo $LIBS"],
[AC_MSG_RESULT([no])])
@@ -95,6 +107,7 @@ 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".])])
@@ -121,16 +134,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 Qt4 should be enabled])
AS_CASE(["x$with_qt4"],
AC_MSG_CHECKING([whether Qt5 should be enabled])
AS_CASE(["x$with_qt5"],
["xno"],
[AC_MSG_RESULT([no])
FIND_QT5()],
FIND_QT4()],
["xyes"],
[AC_MSG_RESULT([yes])
FIND_QT4()],
[AC_MSG_RESULT([$with_qt4])
AC_MSG_ERROR([Unknown option "$with_qt4". Use either "yes" or "no".])])
FIND_QT5()],
[AC_MSG_RESULT([$with_qt5])
AC_MSG_ERROR([Unknown option "$with_qt5". Use either "yes" or "no".])])
AS_IF([test "x$QT_QMAKE" = "x"],
[AC_MSG_ERROR([Could not find qmake])
])
@@ -168,6 +181,34 @@ 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-raser 0.16.x])
AS_CASE(["x$with_libtorrent_rasterbar0_16"],
["xno"],
[AC_MSG_RESULT([no])
PKG_CHECK_MODULES(libtorrent,
[libtorrent-rasterbar >= 1.0.0],
[CPPFLAGS="$libtorrent_CFLAGS $CPPFLAGS"
LIBS="$libtorrent_LIBS $LIBS"])],
["xyes"],
[AC_MSG_RESULT([yes])
PKG_CHECK_MODULES(libtorrent,
[libtorrent-rasterbar >= 0.16.0],
[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"],
@@ -179,7 +220,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_qt4" = "xyes"],
AS_IF([test "x$with_qt5" = "xno"],
[AC_MSG_CHECKING([which qjson to use])
AS_CASE(["x$with_qjson"],
["xshipped"],
@@ -196,11 +237,6 @@ AS_IF([test "x$with_qt4" = "xyes"],
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"
@@ -215,18 +251,15 @@ AX_DEFINE_DIR([EXPAND_MANDIR], [mandir])
# Original extract() function contributed by pmzqla
# $*: Strings to parse
# Set $QBT_CONF_DEFINES, $QBT_CONF_INCLUDES, $QBT_CONF_EXTRA_CFLAGS
# Set $DEFINES, $INCLUDES, $OTHER
extract() {
if [[ -z "$*" ]]; then
echo "Input string required"
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: -:\\${new_line}:g" -e 's:"\(.*\)\n\(.*\)":\"\1 -\2":g' -e "s:'\(.*\)\n\(.*\)':\'\1 -\2':g" -e 's/^[[:space:]]*//')
# Convert " -" to "\n" if not between quotes
string=$(echo " $*" | $SED -e 's: -:\n:g' -e 's:"\(.*\)\n\(.*\)":\"\1 -\2":g' -e "s:'\(.*\)\n\(.*\)':\'\1 -\2':g")
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.3.1</string>
<string>3.2.0</string>
<key>CFBundleSignature</key>
<string>qBit</string>
<key>CFBundleExecutable</key>

View File

@@ -57,5 +57,5 @@
</screenshot>
</screenshots>
<url type="homepage">http://www.qbittorrent.org/</url>
<update_contact>sledgehammer999@qbittorrent.org</update_contact>
<updatecontact>sledgehammer999@qbittorrent.org</updatecontact>
</component>

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 translations for qbt itself
4)the same way you provide the tranlations for qbt itself
PACKAGERS:
@@ -41,10 +41,7 @@ installer-translations
translations
qt_ar.qm
...
(all the .qm files found in the 'translations' folder of your Qt install. Those files differ between Qt4 and Qt5.
If you want to distribute Qt4 translations it is better to use the ones found in this repo under the path "dist/qt-translations".
They contain extra languages not distributed via the official qt4 sources.
Don't forget to edit the filelist in installer.nsi + uninstaller.nsi to include all your .qm files.)
(all the .qm files found in dist/qt-translations in every source release)
qt_zh_TW.qm
installer.nsi
license.txt

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 auf dem Desktop erstellen"
LangString inst_dekstop ${LANG_GERMAN} "Verknüpfung am 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 aus der Windows Firewall"
LangString remove_firewallinfo ${LANG_GERMAN} "Entferne Regel in 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üpfung mit .torrent-Dateien konnte nicht entfernt werden, da dieser Typ mit diesem Programm verknüpft ist:"
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_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:"
LangString uninst_mag_warn ${LANG_GERMAN} "Dateiverknüpfung mit Magnet-Links konnte nicht entfernt werden, da dieser Typ mit diesem Programm verknüpft ist:"
LangString uninst_mag_warn ${LANG_GERMAN} "Dateiverknüfung mit Magnet-Links konnte nicht entfernt werden, da dieser Typ mit diesem Programm verknüpft ist:"

View File

@@ -31,13 +31,13 @@ Section $(inst_qbt_req) ;"qBittorrent (required)"
File "qbittorrent.pdb"
File "qt.conf"
File /oname=translations\qt_ar.qm "translations\qt_ar.qm"
File /oname=translations\qt_bg.qm "translations\qt_bg.qm"
File /oname=translations\qt_ca.qm "translations\qt_ca.qm"
File /oname=translations\qt_cs.qm "translations\qt_cs.qm"
File /oname=translations\qt_da.qm "translations\qt_da.qm"
File /oname=translations\qt_de.qm "translations\qt_de.qm"
File /oname=translations\qt_en.qm "translations\qt_en.qm"
File /oname=translations\qt_es.qm "translations\qt_es.qm"
File /oname=translations\qt_fa.qm "translations\qt_fa.qm"
File /oname=translations\qt_eu.qm "translations\qt_eu.qm"
File /oname=translations\qt_fi.qm "translations\qt_fi.qm"
File /oname=translations\qt_fr.qm "translations\qt_fr.qm"
File /oname=translations\qt_gl.qm "translations\qt_gl.qm"
@@ -47,15 +47,17 @@ Section $(inst_qbt_req) ;"qBittorrent (required)"
File /oname=translations\qt_ja.qm "translations\qt_ja.qm"
File /oname=translations\qt_ko.qm "translations\qt_ko.qm"
File /oname=translations\qt_lt.qm "translations\qt_lt.qm"
File /oname=translations\qt_nl.qm "translations\qt_nl.qm"
File /oname=translations\qt_pl.qm "translations\qt_pl.qm"
File /oname=translations\qt_pt.qm "translations\qt_pt.qm"
File /oname=translations\qt_pt_BR.qm "translations\qt_pt_BR.qm"
File /oname=translations\qt_ru.qm "translations\qt_ru.qm"
File /oname=translations\qt_sk.qm "translations\qt_sk.qm"
File /oname=translations\qt_sl.qm "translations\qt_sl.qm"
File /oname=translations\qt_sk.qm "translations\qt_sk.qm"
File /oname=translations\qt_sv.qm "translations\qt_sv.qm"
File /oname=translations\qt_tr.qm "translations\qt_tr.qm"
File /oname=translations\qt_uk.qm "translations\qt_uk.qm"
File /oname=translations\qt_zh_CN.qm "translations\qt_zh_CN.qm"
File /oname=translations\qt_zh_TW.qm "translations\qt_zh_TW.qm"
File /oname=translations\qt_zh_TW.qm "translations\qt_zh_TW.qm"
; Write the installation path into the registry
WriteRegStr HKLM "Software\qBittorrent" "InstallLocation" "$INSTDIR"

View File

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

View File

@@ -6,12 +6,13 @@
Delete "$INSTDIR\qbittorrent.pdb"
Delete "$INSTDIR\qt.conf"
Delete "$INSTDIR\translations\qt_ar.qm"
Delete "$INSTDIR\translations\qt_bg.qm"
Delete "$INSTDIR\translations\qt_ca.qm"
Delete "$INSTDIR\translations\qt_cs.qm"
Delete "$INSTDIR\translations\qt_da.qm"
Delete "$INSTDIR\translations\qt_de.qm"
Delete "$INSTDIR\translations\qt_en.qm"
Delete "$INSTDIR\translations\qt_es.qm"
Delete "$INSTDIR\translations\qt_eu.qm"
Delete "$INSTDIR\translations\qt_fa.qm"
Delete "$INSTDIR\translations\qt_fi.qm"
Delete "$INSTDIR\translations\qt_fr.qm"
@@ -22,15 +23,18 @@
Delete "$INSTDIR\translations\qt_ja.qm"
Delete "$INSTDIR\translations\qt_ko.qm"
Delete "$INSTDIR\translations\qt_lt.qm"
Delete "$INSTDIR\translations\qt_nl.qm"
Delete "$INSTDIR\translations\qt_pl.qm"
Delete "$INSTDIR\translations\qt_pt.qm"
Delete "$INSTDIR\translations\qt_pt_BR.qm"
Delete "$INSTDIR\translations\qt_ru.qm"
Delete "$INSTDIR\translations\qt_sk.qm"
Delete "$INSTDIR\translations\qt_sl.qm"
Delete "$INSTDIR\translations\qt_sv.qm"
Delete "$INSTDIR\translations\qt_tr.qm"
Delete "$INSTDIR\translations\qt_uk.qm"
Delete "$INSTDIR\translations\qt_zh_CN.qm"
Delete "$INSTDIR\translations\qt_zh_TW.qm"
Delete "$INSTDIR\translations\qt_zh_TW.qm"
Delete "$INSTDIR\uninst.exe"
; Remove directories used

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 reproducible bug are accepted. :-)
Only bug reports with a reproducable 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 26
#serial 23
AC_DEFUN([AX_BOOST_BASE],
[
@@ -92,11 +92,8 @@ if test "x$want_boost" = "xyes"; then
libsubdirs="lib"
ax_arch=`uname -m`
case $ax_arch in
x86_64)
libsubdirs="lib64 libx32 lib lib64"
;;
ppc64|s390x|sparc64|aarch64|ppc64le)
libsubdirs="lib64 lib lib64 ppc64le"
x86_64|ppc64|s390x|sparc64|aarch64)
libsubdirs="lib64 lib lib64"
;;
esac
@@ -173,10 +170,6 @@ 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
@@ -189,12 +182,6 @@ 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_qt4" = "xno"],
[AS_IF([test "x$with_qt5" = "xyes"],
[AC_MSG_CHECKING([for Qt5DBus >= 5.2.0])
PKG_CHECK_EXISTS([Qt5DBus >= 5.2.0],
[AC_MSG_RESULT([found])

View File

@@ -10,9 +10,7 @@ exists($$OUT_PWD/../conf.pri) {
}
LIBS += -framework Carbon -framework IOKit
# C++11 support
lessThan(QT_MAJOR_VERSION, 5): QMAKE_CXXFLAGS += -std=c++11
CONFIG += c++11
QT_LANG_PATH = ../dist/qt-translations
DIST_PATH = ../dist/mac
@@ -58,3 +56,6 @@ 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,6 +1,3 @@
# 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)
@@ -16,4 +13,8 @@ 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,6 +27,3 @@ strace_win {
}
SOURCES += $$PWD/main.cpp
# upgrade code
HEADERS += $$PWD/upgrade.h

View File

@@ -32,10 +32,8 @@
#include <QLocale>
#include <QLibraryInfo>
#include <QSysInfo>
#include <QProcess>
#ifndef DISABLE_GUI
#include "gui/guiiconprovider.h"
#ifdef Q_OS_WIN
#include <Windows.h>
#include <QSharedMemory>
@@ -48,40 +46,26 @@
#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 "base/logger.h"
#include "base/preferences.h"
#include "base/utils/fs.h"
#include "base/utils/misc.h"
#include "base/iconprovider.h"
#include "base/scanfoldersmodel.h"
#include "base/net/smtp.h"
#include "base/net/downloadmanager.h"
#include "base/net/geoipmanager.h"
#include "base/bittorrent/session.h"
#include "base/bittorrent/torrenthandle.h"
#include "logger.h"
#include "preferences.h"
#include "qbtsession.h"
#include "torrentpersistentdata.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
@@ -101,8 +85,6 @@ 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)
@@ -116,94 +98,6 @@ 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)));
@@ -220,36 +114,45 @@ 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 (Preferences::instance()->useAdditionDialog())
AddNewTorrentDialog::show(param, m_window);
else
if (useTorrentAdditionDialog)
AddNewTorrentDialog::showMagnet(param, m_window);
else
#endif
BitTorrent::Session::instance()->addTorrent(param);
QBtSession::instance()->addMagnetUri(param);
}
else {
#ifndef DISABLE_GUI
if (useTorrentAdditionDialog)
AddNewTorrentDialog::showTorrent(param, QString(), m_window);
else
#endif
QBtSession::instance()->addTorrent(param);
}
}
}
}
int Application::exec(const QStringList &params)
{
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);
// Resume unfinished torrents
QBtSession::instance()->startUpTorrents();
#ifndef DISABLE_WEBUI
m_webui = new WebUI;
@@ -319,10 +222,10 @@ bool Application::event(QEvent *ev)
// Get the url instead
path = static_cast<QFileOpenEvent *>(ev)->url().toString();
qDebug("Received a mac file open event: %s", qPrintable(path));
if (m_running)
if (running_)
processParams(QStringList(path));
else
m_paramsQueue.append(path);
paramsQueue_.append(path);
return true;
}
else {
@@ -350,14 +253,13 @@ void Application::initializeTranslation()
Preferences* const pref = Preferences::instance();
// Load translation
QString locale = pref->getLocale();
if (locale.isEmpty()) {
locale = QLocale::system().name();
pref->setLocale(locale);
}
if (m_qtTranslator.load(
#ifdef QBT_USES_QT5
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
QString::fromUtf8("qtbase_") + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath)) ||
m_qtTranslator.load(
#endif
@@ -391,8 +293,6 @@ 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
@@ -456,16 +356,10 @@ void Application::cleanup()
#ifndef DISABLE_WEBUI
delete m_webui;
#endif
ScanFoldersModel::freeInstance();
BitTorrent::Session::freeInstance();
#ifndef DISABLE_COUNTRIES_RESOLUTION
Net::GeoIPManager::freeInstance();
#endif
Preferences::freeInstance();
Logger::freeInstance();
IconProvider::freeInstance();
Net::DownloadManager::freeInstance();
QBtSession::drop();
TorrentPersistentData::drop();
Preferences::drop();
Logger::drop();
#ifndef DISABLE_GUI
#ifdef Q_OS_WIN
typedef BOOL (WINAPI *PSHUTDOWNBRDESTROY)(HWND);
@@ -475,9 +369,6 @@ 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,17 +50,10 @@ QT_END_NAMESPACE
typedef QtSingleCoreApplication BaseApplication;
#endif
#include "base/utils/misc.h"
#ifndef DISABLE_WEBUI
class WebUI;
#endif
namespace BitTorrent
{
class TorrentHandle;
}
class Application : public BaseApplication
{
Q_OBJECT
@@ -84,8 +77,6 @@ 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);
@@ -96,7 +87,6 @@ private:
#ifndef DISABLE_GUI
QPointer<MainWindow> m_window;
ShutdownAction m_shutdownAct;
#endif
#ifndef DISABLE_WEBUI
@@ -109,7 +99,6 @@ private:
void initializeTranslation();
void processParams(const QStringList &params);
void sendNotificationEmail(BitTorrent::TorrentHandle *const torrent);
};
#endif // APPLICATION_H

View File

@@ -33,7 +33,6 @@
#include <QScopedPointer>
#ifndef DISABLE_GUI
// GUI-only includes
#include <QFont>
#include <QMessageBox>
#include <QPainter>
@@ -42,19 +41,14 @@
#include <QSplashScreen>
#ifdef QBT_STATIC_QT
#include <QtPlugin>
#ifdef QBT_USES_QT5
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
Q_IMPORT_PLUGIN(QICOPlugin)
#else
Q_IMPORT_PLUGIN(qico)
#endif
#endif // QBT_STATIC_QT
#else
// NoGUI-only includes
#else // DISABLE_GUI
#include <cstdio>
#ifdef Q_OS_UNIX
#include "unistd.h"
#endif
#endif // DISABLE_GUI
#ifdef Q_OS_UNIX
@@ -72,10 +66,9 @@ Q_IMPORT_PLUGIN(qico)
#include <cstdlib>
#include <iostream>
#include "application.h"
#include "base/utils/misc.h"
#include "base/preferences.h"
#include "upgrade.h"
#include "misc.h"
#include "preferences.h"
#include "logger.h"
// Signal handlers
#if defined(Q_OS_UNIX) || defined(STACKTRACE_WIN)
@@ -127,11 +120,13 @@ 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-") + Utils::Misc::getUserIDString();
QString appId = QLatin1String("qBittorrent-") + misc::getUserIDString();
QScopedPointer<Application> app(new Application(appId, argc, argv));
const QBtCommandLineParameters params = parseCommandLine();
@@ -181,16 +176,8 @@ 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()) {
@@ -204,20 +191,12 @@ int main(int argc, char *argv[])
#endif
qDebug("qBittorrent is already running for this user.");
Utils::Misc::msleep(300);
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) {
@@ -400,7 +379,7 @@ QString makeUsage(const QString &prg_name)
#endif
text += QLatin1String("\t-h | --help\t\t") + QObject::tr("Displays this help message") + QLatin1Char('\n');
text += QLatin1String("\t--webui-port=<port>\t")
+ QObject::tr("Changes the Web UI port (current: %1)").arg(QString::number(Preferences::instance()->getWebUiPort()))
+ QObject::tr("Changes the webui port (current: %1)").arg(QString::number(Preferences::instance()->getWebUiPort()))
+ QLatin1Char('\n');
#ifndef DISABLE_GUI
text += QLatin1String("\t--no-splash\t\t") + QObject::tr("Disable splash screen") + QLatin1Char('\n');
@@ -419,7 +398,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(Utils::Misc::screenCenter(&msgBox));
msgBox.move(misc::screenCenter(&msgBox));
msgBox.exec();
#endif
}
@@ -431,7 +410,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(Utils::Misc::screenCenter(&msgBox));
msgBox.move(misc::screenCenter(&msgBox));
msgBox.exec();
#else
std::cerr << qPrintable(QObject::tr("Bad command line: "));
@@ -463,7 +442,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(Utils::Misc::screenCenter(&msgBox));
msgBox.move(misc::screenCenter(&msgBox));
msgBox.exec();
if (msgBox.clickedButton() == agree_button) {
// Save the answer

View File

@@ -41,7 +41,6 @@
#include "qtlocalpeer.h"
#include <QCoreApplication>
#include <QDataStream>
#include <QTime>
#if defined(Q_OS_WIN)

View File

@@ -1,177 +0,0 @@
/*
* 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 "base/logger.h"
#include "base/utils/fs.h"
#include "base/utils/misc.h"
#include "base/utils/string.h"
#include "base/qinisettings.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, const QVariantHash &oldTorrent, int &maxPrio)
{
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");
if (priority > maxPrio)
maxPrio = priority;
fastNew["qBt-name"] = Utils::String::toStdString(oldTorrent.value("name").toString());
fastNew["qBt-tempPathDisabled"] = false;
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)
{
QIniSettings *oldResumeSettings = new QIniSettings("qBittorrent", "qBittorrent-resume");
QString oldResumeFilename = oldResumeSettings->fileName();
QVariantHash oldResumeData = oldResumeSettings->value("torrents").toHash();
delete oldResumeSettings;
if (oldResumeData.isEmpty())
Utils::Fs::forceRemove(oldResumeFilename);
QString backupFolderPath = Utils::Fs::expandPathAbs(Utils::Fs::QDesktopServicesDataLocation() + "BT_backup");
QDir backupFolderDir(backupFolderPath);
QStringList backupFiles = backupFolderDir.entryList(QStringList() << QLatin1String("*.fastresume"), QDir::Files, QDir::Unsorted);
if (backupFiles.isEmpty() && oldResumeData.isEmpty()) return true;
if (ask && !userAcceptsUpgrade()) return false;
int maxPrio = 0;
QRegExp rx(QLatin1String("^([A-Fa-f0-9]{40})\\.fastresume$"));
foreach (QString backupFile, backupFiles) {
if (rx.indexIn(backupFile) != -1) {
if (upgradeResumeFile(backupFolderDir.absoluteFilePath(backupFile), oldResumeData[rx.cap(1)].toHash(), maxPrio))
oldResumeData.remove(rx.cap(1));
else
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);
}
}
foreach (const QString &hash, oldResumeData.keys()) {
QVariantHash oldTorrent = oldResumeData[hash].toHash();
if (oldTorrent.value("is_magnet", false).toBool()) {
libtorrent::entry resumeData;
resumeData["qBt-magnetUri"] = Utils::String::toStdString(oldTorrent.value("magnet_uri").toString());
resumeData["qBt-paused"] = false;
resumeData["qBt-forced"] = false;
resumeData["qBt-savePath"] = Utils::String::toStdString(oldTorrent.value("save_path").toString());
resumeData["qBt-ratioLimit"] = Utils::String::toStdString(QString::number(oldTorrent.value("max_ratio", -2).toReal()));
resumeData["qBt-label"] = Utils::String::toStdString(oldTorrent.value("label").toString());
resumeData["qBt-name"] = Utils::String::toStdString(oldTorrent.value("name").toString());
resumeData["qBt-seedStatus"] = oldTorrent.value("seed").toBool();
resumeData["qBt-tempPathDisabled"] = false;
QString filename = QString("%1.fastresume.%2").arg(hash).arg(++maxPrio);
QString filepath = backupFolderDir.absoluteFilePath(filename);
QFile resumeFile(filepath);
QVector<char> out;
libtorrent::bencode(std::back_inserter(out), resumeData);
if (resumeFile.open(QIODevice::WriteOnly))
resumeFile.write(&out[0], out.size());
}
}
if (!oldResumeData.isEmpty())
QFile(oldResumeFilename).rename(oldResumeFilename + ".bak");
return true;
}
#endif // UPGRADE_H

View File

@@ -1,86 +0,0 @@
HEADERS += \
$$PWD/types.h \
$$PWD/tristatebool.h \
$$PWD/filesystemwatcher.h \
$$PWD/qinisettings.h \
$$PWD/logger.h \
$$PWD/preferences.h \
$$PWD/iconprovider.h \
$$PWD/http/irequesthandler.h \
$$PWD/http/connection.h \
$$PWD/http/requestparser.h \
$$PWD/http/responsegenerator.h \
$$PWD/http/server.h \
$$PWD/http/types.h \
$$PWD/http/responsebuilder.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/tristatebool.cpp \
$$PWD/filesystemwatcher.cpp \
$$PWD/logger.cpp \
$$PWD/preferences.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/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,64 +0,0 @@
/*
* 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

@@ -1,53 +0,0 @@
/*
* 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

@@ -1,98 +0,0 @@
/*
* 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

@@ -1,93 +0,0 @@
/*
* 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 "base/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

@@ -1,68 +0,0 @@
/*
* 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

@@ -1,410 +0,0 @@
/*
* 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 "base/net/geoipmanager.h"
#include "base/utils/string.h"
#include "base/unicodestrings.h"
#include "base/bittorrent/torrenthandle.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 TorrentHandle *torrent, const libt::peer_info &nativeInfo)
: m_nativeInfo(nativeInfo)
{
calcRelevance(torrent);
determineFlags();
}
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;
}
void PeerInfo::calcRelevance(const TorrentHandle *torrent)
{
const QBitArray &allPieces = torrent->pieces();
const QBitArray &peerPieces = pieces();
int localMissing = 0;
int remoteHaves = 0;
for (int i = 0; i < allPieces.size(); ++i) {
if (!allPieces[i]) {
++localMissing;
if (peerPieces[i])
++remoteHaves;
}
}
if (localMissing == 0)
m_relevance = 0.0;
else
m_relevance = static_cast<qreal>(remoteHaves) / localMissing;
}
qreal PeerInfo::relevance() const
{
return m_relevance;
}
void PeerInfo::determineFlags()
{
if (isInteresting()) {
//d = Your client wants to download, but peer doesn't want to send (interested and choked)
if (isRemoteChocked()) {
m_flags += "d ";
m_flagsDescription += tr("interested(local) and choked(peer)");
m_flagsDescription += ", ";
}
else {
//D = Currently downloading (interested and not choked)
m_flags += "D ";
m_flagsDescription += tr("interested(local) and unchoked(peer)");
m_flagsDescription += ", ";
}
}
if (isRemoteInterested()) {
//u = Peer wants your client to upload, but your client doesn't want to (interested and choked)
if (isChocked()) {
m_flags += "u ";
m_flagsDescription += tr("interested(peer) and choked(local)");
m_flagsDescription += ", ";
}
else {
//U = Currently uploading (interested and not choked)
m_flags += "U ";
m_flagsDescription += tr("interested(peer) and unchoked(local)");
m_flagsDescription += ", ";
}
}
//O = Optimistic unchoke
if (optimisticUnchoke()) {
m_flags += "O ";
m_flagsDescription += tr("optimistic unchoke");
m_flagsDescription += ", ";
}
//S = Peer is snubbed
if (isSnubbed()) {
m_flags += "S ";
m_flagsDescription += tr("peer snubbed");
m_flagsDescription += ", ";
}
//I = Peer is an incoming connection
if (!isLocalConnection()) {
m_flags += "I ";
m_flagsDescription += tr("incoming connection");
m_flagsDescription += ", ";
}
//K = Peer is unchoking your client, but your client is not interested
if (!isRemoteChocked() && !isInteresting()) {
m_flags += "K ";
m_flagsDescription += tr("not interested(local) and unchoked(peer)");
m_flagsDescription += ", ";
}
//? = Your client unchoked the peer but the peer is not interested
if (!isChocked() && !isRemoteInterested()) {
m_flags += "? ";
m_flagsDescription += tr("not interested(peer) and unchoked(local)");
m_flagsDescription += ", ";
}
//X = Peer was included in peerlists obtained through Peer Exchange (PEX)
if (fromPeX()) {
m_flags += "X ";
m_flagsDescription += tr("peer from PEX");
m_flagsDescription += ", ";
}
//H = Peer was obtained through DHT
if (fromDHT()) {
m_flags += "H ";
m_flagsDescription += tr("peer from DHT");
m_flagsDescription += ", ";
}
//E = Peer is using Protocol Encryption (all traffic)
if (isRC4Encrypted()) {
m_flags += "E ";
m_flagsDescription += tr("encrypted traffic");
m_flagsDescription += ", ";
}
//e = Peer is using Protocol Encryption (handshake)
if (isPlaintextEncrypted()) {
m_flags += "e ";
m_flagsDescription += tr("encrypted handshake");
m_flagsDescription += ", ";
}
//P = Peer is using uTorrent uTP
if (useUTPSocket()) {
m_flags += "P ";
m_flagsDescription += QString::fromUtf8(C_UTP);
m_flagsDescription += ", ";
}
//L = Peer is local
if (fromLSD()) {
m_flags += "L";
m_flagsDescription += tr("peer from LSD");
}
m_flags = m_flags.trimmed();
m_flagsDescription = m_flagsDescription.trimmed();
if (m_flagsDescription.endsWith(',', Qt::CaseInsensitive))
m_flagsDescription.chop(1);
}
QString PeerInfo::flags() const
{
return m_flags;
}
QString PeerInfo::flagsDescription() const
{
return m_flagsDescription;
}

View File

@@ -1,115 +0,0 @@
/*
* 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>
#include <QCoreApplication>
namespace BitTorrent
{
class TorrentHandle;
struct PeerAddress
{
QHostAddress ip;
ushort port;
PeerAddress();
PeerAddress(QHostAddress ip, ushort port);
};
class PeerInfo
{
Q_DECLARE_TR_FUNCTIONS(PeerInfo)
public:
PeerInfo(const TorrentHandle *torrent, 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;
qreal relevance() const;
QString flags() const;
QString flagsDescription() const;
#ifndef DISABLE_COUNTRIES_RESOLUTION
QString country() const;
#endif
private:
void calcRelevance(const TorrentHandle *torrent);
void determineFlags();
libtorrent::peer_info m_nativeInfo;
qreal m_relevance;
QString m_flags;
QString m_flagsDescription;
};
}
#endif // BITTORRENT_PEERINFO_H

View File

@@ -1,96 +0,0 @@
/*
* 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 "base/preferences.h"
#include "bandwidthscheduler.h"
BandwidthScheduler::BandwidthScheduler(QObject *parent)
: QTimer(parent)
{
Q_ASSERT(Preferences::instance()->isSchedulerEnabled());
// Single shot, we call start() again manually
setSingleShot(true);
// Connect Signals/Slots
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,439 +0,0 @@
/*
* 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 "base/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,56 +0,0 @@
/*
* 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,84 +0,0 @@
/*
* 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.
*/
#ifndef SPEEDMONITOR_H
#define SPEEDMONITOR_H
template<typename T> class QList;
template<typename T>
struct Sample
{
Sample()
: download()
, upload()
{
}
Sample(T dl, T ul)
: download(dl)
, upload(ul)
{
}
Sample<T> &operator+=(const Sample<T> &other)
{
download += other.download;
upload += other.upload;
return *this;
}
Sample<T> &operator-=(const Sample<T> &other)
{
download -= other.download;
upload -= other.upload;
return *this;
}
T download;
T upload;
};
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

File diff suppressed because it is too large Load Diff

View File

@@ -1,375 +0,0 @@
/*
* 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 "base/tristatebool.h"
#include "base/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 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

@@ -1,136 +0,0 @@
/*
* 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

@@ -1,79 +0,0 @@
/*
* 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

@@ -1,165 +0,0 @@
/*
* 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 "base/utils/fs.h"
#include "base/utils/misc.h"
#include "base/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,73 +0,0 @@
/*
* 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
*/
#ifndef BITTORRENT_TORRENTCREATORTHREAD_H
#define BITTORRENT_TORRENTCREATORTHREAD_H
#include <QThread>
#include <QStringList>
namespace BitTorrent
{
class TorrentCreatorThread : public QThread
{
Q_OBJECT
public:
TorrentCreatorThread(QObject *parent = 0);
~TorrentCreatorThread();
void create(const QString &inputPath, const QString &savePath, const QStringList &trackers,
const QStringList &urlSeeds, const QString &comment, bool isPrivate, int pieceSize);
void abortCreation();
protected:
void run();
signals:
void creationFailure(const QString &msg);
void creationSuccess(const QString &path, const QString &branchPath);
void updateProgress(int progress);
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

@@ -1,418 +0,0 @@
/*
* 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 "base/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

@@ -1,223 +0,0 @@
/*
* 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 "base/utils/misc.h"
#include "base/utils/fs.h"
#include "base/utils/string.h"
#include "infohash.h"
#include "trackerentry.h"
#include "torrentinfo.h"
namespace libt = libtorrent;
using namespace BitTorrent;
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

@@ -1,87 +0,0 @@
/*
* 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

@@ -1,103 +0,0 @@
/*
* 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 "base/http/types.h"
#include "base/http/responsebuilder.h"
#include "base/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

@@ -1,95 +0,0 @@
/*
* 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 "base/utils/misc.h"
#include "base/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

@@ -1,68 +0,0 @@
/*
* 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,278 +0,0 @@
#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 "base/preferences.h"
#include "base/bittorrent/torrentinfo.h"
#include "base/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

@@ -1,52 +0,0 @@
#ifndef FILESYSTEMWATCHER_H
#define FILESYSTEMWATCHER_H
#include <QFileSystemWatcher>
#include <QDir>
#include <QTimer>
#include <QPointer>
#include <QStringList>
#include <QHash>
/*
* Subclassing QFileSystemWatcher in order to support Network File
* System watching (NFS, CIFS) on Linux and Mac OS.
*/
class FileSystemWatcher : public QFileSystemWatcher
{
Q_OBJECT
public:
explicit FileSystemWatcher(QObject *parent = 0);
~FileSystemWatcher();
QStringList directories() const;
void addPath(const QString &path);
void removePath(const QString &path);
signals:
void torrentsAdded(const QStringList &pathList);
protected slots:
void scanLocalFolder(QString path);
void scanNetworkFolders();
void processPartialTorrents();
private:
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,64 +0,0 @@
/*
* 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,305 +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>
#ifdef QBT_USES_QT5
#include <QUrlQuery>
#endif
#include "base/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");
#ifndef QBT_USES_QT5
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

@@ -1,248 +0,0 @@
/*
* 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 "base/utils/fs.h"
#include "base/utils/gzip.h"
#include "base/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,79 +0,0 @@
/*
* 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_DOWNLOADHANDLER_H
#define NET_DOWNLOADHANDLER_H
#include <QObject>
QT_BEGIN_NAMESPACE
class QNetworkAccessManager;
class QNetworkReply;
class QUrl;
QT_END_NAMESPACE
namespace Net
{
class DownloadManager;
class DownloadHandler : public QObject
{
Q_OBJECT
public:
DownloadHandler(QNetworkReply *reply, DownloadManager *manager, bool saveToFile = false, qint64 limit = 0, bool handleRedirectToMagnet = false);
~DownloadHandler();
QString url() const;
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 slots:
void processFinishedDownload();
void checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal);
private:
void init();
bool saveToFile(const QByteArray &replyData, QString &filePath);
void handleRedirection(QUrl newUrl);
QNetworkReply *m_reply;
DownloadManager *m_manager;
bool m_saveToFile;
qint64 m_sizeLimit;
bool m_handleRedirectToMagnet;
QString m_url;
};
}
#endif // NET_DOWNLOADHANDLER_H

View File

@@ -1,151 +0,0 @@
/*
* 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 "base/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

@@ -1,76 +0,0 @@
/*
* 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

@@ -1,461 +0,0 @@
/*
* 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 "base/logger.h"
#include "base/preferences.h"
#include "base/utils/fs.h"
#include "base/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

@@ -1,76 +0,0 @@
/*
* 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

@@ -1,122 +0,0 @@
/*
* 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 "base/logger.h"
#include "base/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

@@ -1,73 +0,0 @@
/*
* 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

@@ -1,520 +0,0 @@
/*
* 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 "base/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
};
#ifndef QBT_USES_QT5
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
{
#ifndef QBT_USES_QT5
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
{
#ifndef QBT_USES_QT5
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

@@ -1,102 +0,0 @@
/*
* 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,502 +0,0 @@
/*
* 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 "base/preferences.h"
#include "base/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,373 +0,0 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2010 Christian Kandeler, 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 <QDir>
#include <QFileInfo>
#include <QString>
#include <QStringList>
#include <QTemporaryFile>
#include "utils/misc.h"
#include "utils/fs.h"
#include "preferences.h"
#include "filesystemwatcher.h"
#include "bittorrent/session.h"
#include "scanfoldersmodel.h"
namespace
{
const int PathColumn = 0;
const int DownloadAtTorrentColumn = 1;
const int DownloadPath = 2;
}
class ScanFoldersModel::PathData
{
public:
PathData(const QString &path)
: path(path)
, downloadAtPath(false)
, downloadPath(path)
{
}
PathData(const QString &path, bool downloadAtPath, const QString &downloadPath)
: path(path)
, downloadAtPath(downloadAtPath)
, downloadPath(downloadPath)
{
}
const QString path; //watching directory
bool downloadAtPath; //if TRUE save data to watching directory
QString downloadPath; //if 'downloadAtPath' FALSE use this path for save data
};
ScanFoldersModel *ScanFoldersModel::m_instance = 0;
bool ScanFoldersModel::initInstance(QObject *parent)
{
if (!m_instance) {
m_instance = new ScanFoldersModel(parent);
return true;
}
return false;
}
void ScanFoldersModel::freeInstance()
{
if (m_instance) {
delete m_instance;
m_instance = 0;
}
}
ScanFoldersModel *ScanFoldersModel::instance()
{
return m_instance;
}
ScanFoldersModel::ScanFoldersModel(QObject *parent)
: QAbstractTableModel(parent)
, m_fsWatcher(0)
{
configure();
connect(Preferences::instance(), SIGNAL(changed()), SLOT(configure()));
}
ScanFoldersModel::~ScanFoldersModel()
{
qDeleteAll(m_pathList);
}
int ScanFoldersModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_pathList.count();
}
int ScanFoldersModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return 3;
}
QVariant ScanFoldersModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || (index.row() >= rowCount()))
return QVariant();
const PathData *pathData = m_pathList.at(index.row());
QVariant value;
switch (index.column()) {
case PathColumn:
if (role == Qt::DisplayRole)
value = Utils::Fs::toNativePath(pathData->path);
break;
case DownloadAtTorrentColumn:
if (role == Qt::CheckStateRole)
value = pathData->downloadAtPath ? Qt::Checked : Qt::Unchecked;
break;
case DownloadPath:
if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::ToolTipRole)
value = Utils::Fs::toNativePath(pathData->downloadPath);
break;
}
return value;
}
QVariant ScanFoldersModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if ((orientation != Qt::Horizontal) || (role != Qt::DisplayRole) || (section < 0) || (section >= columnCount()))
return QVariant();
QVariant title;
switch (section) {
case PathColumn:
title = tr("Watched Folder");
break;
case DownloadAtTorrentColumn:
title = tr("Download here");
break;
case DownloadPath:
title = tr("Download path");
break;
}
return title;
}
Qt::ItemFlags ScanFoldersModel::flags(const QModelIndex &index) const
{
if (!index.isValid() || (index.row() >= rowCount()))
return QAbstractTableModel::flags(index);
const PathData *pathData = m_pathList.at(index.row());
Qt::ItemFlags flags;
switch (index.column()) {
case PathColumn:
flags = QAbstractTableModel::flags(index);
break;
case DownloadAtTorrentColumn:
flags = QAbstractTableModel::flags(index) | Qt::ItemIsUserCheckable;
break;
case DownloadPath:
if (pathData->downloadAtPath == false)
flags = QAbstractTableModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsEnabled;
else
flags = QAbstractTableModel::flags(index) ^ Qt::ItemIsEnabled; //dont edit DownloadPath if checked 'downloadAtPath'
break;
}
return flags;
}
bool ScanFoldersModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid() || (index.row() >= rowCount()) || (index.column() > DownloadPath))
return false;
bool success = true;
switch (index.column()) {
case PathColumn:
success = false;
break;
case DownloadAtTorrentColumn:
if (role == Qt::CheckStateRole) {
Q_ASSERT(index.column() == DownloadAtTorrentColumn);
m_pathList[index.row()]->downloadAtPath = (value.toInt() == Qt::Checked);
emit dataChanged(index, index);
success = true;
}
break;
case DownloadPath:
Q_ASSERT(index.column() == DownloadPath);
m_pathList[index.row()]->downloadPath = value.toString();
emit dataChanged(index, index);
success = true;
break;
}
return success;
}
ScanFoldersModel::PathStatus ScanFoldersModel::addPath(const QString &path, bool downloadAtPath, const QString &downloadPath)
{
QDir dir(path);
if (!dir.exists()) return DoesNotExist;
if (!dir.isReadable()) return CannotRead;
const QString &canonicalPath = dir.canonicalPath();
if (findPathData(canonicalPath) != -1) return AlreadyInList;
if (!m_fsWatcher) {
m_fsWatcher = new FileSystemWatcher(this);
connect(m_fsWatcher, SIGNAL(torrentsAdded(const QStringList &)), this, SLOT(addTorrentsToSession(const QStringList &)));
}
beginInsertRows(QModelIndex(), rowCount(), rowCount());
QString downloadToPath = downloadPath.isEmpty() ? path : downloadPath;
m_pathList << new PathData(canonicalPath, downloadAtPath, downloadToPath);
endInsertRows();
// Start scanning
m_fsWatcher->addPath(canonicalPath);
return Ok;
}
void ScanFoldersModel::removePath(int row)
{
Q_ASSERT((row >= 0) && (row < rowCount()));
beginRemoveRows(QModelIndex(), row, row);
m_fsWatcher->removePath(m_pathList.at(row)->path);
m_pathList.removeAt(row);
endRemoveRows();
}
bool ScanFoldersModel::removePath(const QString &path)
{
const int row = findPathData(path);
if (row == -1) return false;
removePath(row);
return true;
}
ScanFoldersModel::PathStatus ScanFoldersModel::setDownloadAtPath(int row, bool downloadAtPath)
{
Q_ASSERT((row >= 0) && (row < rowCount()));
bool &oldValue = m_pathList[row]->downloadAtPath;
if (oldValue != downloadAtPath) {
if (downloadAtPath) {
QTemporaryFile testFile(m_pathList[row]->path + "/tmpFile");
if (!testFile.open()) return CannotWrite;
}
oldValue = downloadAtPath;
const QModelIndex changedIndex = index(row, DownloadAtTorrentColumn);
emit dataChanged(changedIndex, changedIndex);
}
return Ok;
}
bool ScanFoldersModel::downloadInTorrentFolder(const QString &filePath) const
{
const int row = findPathData(QFileInfo(filePath).dir().path());
Q_ASSERT(row != -1);
return m_pathList.at(row)->downloadAtPath;
}
QString ScanFoldersModel::downloadPathTorrentFolder(const QString &filePath) const
{
const int row = findPathData(QFileInfo(filePath).dir().path());
Q_ASSERT(row != -1);
return m_pathList.at(row)->downloadPath;
}
int ScanFoldersModel::findPathData(const QString &path) const
{
for (int i = 0; i < m_pathList.count(); ++i)
if (m_pathList.at(i)->path == Utils::Fs::fromNativePath(path))
return i;
return -1;
}
void ScanFoldersModel::makePersistent()
{
Preferences *const pref = Preferences::instance();
QStringList paths;
QList<bool> downloadInFolderInfo;
QStringList downloadPaths;
foreach (const PathData *pathData, m_pathList) {
paths << pathData->path;
downloadInFolderInfo << pathData->downloadAtPath;
downloadPaths << pathData->downloadPath;
}
pref->setScanDirs(paths);
pref->setDownloadInScanDirs(downloadInFolderInfo);
pref->setScanDirsDownloadPaths(downloadPaths);
}
void ScanFoldersModel::configure()
{
Preferences *const pref = Preferences::instance();
int i = 0;
QStringList downloadPaths = pref->getScanDirsDownloadPaths();
QList<bool> downloadInDirList = pref->getDownloadInScanDirs();
foreach (const QString &dir, pref->getScanDirs()) {
bool downloadInDir = downloadInDirList.value(i, true);
QString downloadPath = downloadPaths.value(i); //empty string if out-of-bounds
addPath(dir, downloadInDir, downloadPath);
++i;
}
}
void ScanFoldersModel::addTorrentsToSession(const QStringList &pathList)
{
foreach (const QString &file, pathList) {
qDebug("File %s added", qPrintable(file));
if (file.endsWith(".magnet")) {
QFile f(file);
if (f.open(QIODevice::ReadOnly)) {
BitTorrent::Session::instance()->addTorrent(QString::fromLocal8Bit(f.readAll()));
f.remove();
}
else {
qDebug("Failed to open magnet file: %s", qPrintable(f.errorString()));
}
}
else {
BitTorrent::AddTorrentParams params;
if (downloadInTorrentFolder(file))
params.savePath = QFileInfo(file).dir().path();
else
params.savePath = downloadPathTorrentFolder(file); //if empty it will use the default savePath
BitTorrent::TorrentInfo torrentInfo = BitTorrent::TorrentInfo::loadFromFile(file);
if (torrentInfo.isValid()) {
BitTorrent::Session::instance()->addTorrent(torrentInfo, params);
Utils::Fs::forceRemove(file);
}
else {
qDebug("Ignoring incomplete torrent file: %s", qPrintable(file));
}
}
}
}

View File

@@ -1,96 +0,0 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2010 Christian Kandeler, 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 SCANFOLDERSMODEL_H
#define SCANFOLDERSMODEL_H
#include <QAbstractTableModel>
#include <QList>
QT_BEGIN_NAMESPACE
class QStringList;
QT_END_NAMESPACE
class FileSystemWatcher;
class ScanFoldersModel : public QAbstractTableModel
{
Q_OBJECT
Q_DISABLE_COPY(ScanFoldersModel)
public:
enum PathStatus
{
Ok,
DoesNotExist,
CannotRead,
CannotWrite,
AlreadyInList
};
static bool initInstance(QObject *parent = 0);
static void freeInstance();
static ScanFoldersModel *instance();
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
// TODO: removePaths(); singular version becomes private helper functions;
// also: remove functions should take modelindexes
PathStatus addPath(const QString &path, bool downloadAtPath, const QString &downloadPath);
void removePath(int row);
bool removePath(const QString &path);
PathStatus setDownloadAtPath(int row, bool downloadAtPath);
bool downloadInTorrentFolder(const QString &filePath) const;
QString downloadPathTorrentFolder(const QString &filePath) const;
void makePersistent();
private slots:
void configure();
void addTorrentsToSession(const QStringList &pathList);
private:
explicit ScanFoldersModel(QObject *parent = 0);
~ScanFoldersModel();
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
static ScanFoldersModel *m_instance;
class PathData;
int findPathData(const QString &path) const;
QList<PathData*> m_pathList;
FileSystemWatcher *m_fsWatcher;
};
#endif // SCANFOLDERSMODEL_H

View File

@@ -1,168 +0,0 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2014 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 "bittorrent/torrenthandle.h"
#include "torrentfilter.h"
const QString TorrentFilter::AnyLabel;
const QStringSet TorrentFilter::AnyHash = (QStringSet() << QString());
const TorrentFilter TorrentFilter::DownloadingTorrent(TorrentFilter::Downloading);
const TorrentFilter TorrentFilter::SeedingTorrent(TorrentFilter::Seeding);
const TorrentFilter TorrentFilter::CompletedTorrent(TorrentFilter::Completed);
const TorrentFilter TorrentFilter::PausedTorrent(TorrentFilter::Paused);
const TorrentFilter TorrentFilter::ResumedTorrent(TorrentFilter::Resumed);
const TorrentFilter TorrentFilter::ActiveTorrent(TorrentFilter::Active);
const TorrentFilter TorrentFilter::InactiveTorrent(TorrentFilter::Inactive);
const TorrentFilter TorrentFilter::ErroredTorrent(TorrentFilter::Errored);
using BitTorrent::TorrentHandle;
using BitTorrent::TorrentState;
TorrentFilter::TorrentFilter()
: m_type(All)
{
}
TorrentFilter::TorrentFilter(Type type, QStringSet hashSet, QString label)
: m_type(type)
, m_label(label)
, m_hashSet(hashSet)
{
}
TorrentFilter::TorrentFilter(QString filter, QStringSet hashSet, QString label)
: m_type(All)
, m_label(label)
, m_hashSet(hashSet)
{
setTypeByName(filter);
}
bool TorrentFilter::setType(Type type)
{
if (m_type != type) {
m_type = type;
return true;
}
return false;
}
bool TorrentFilter::setTypeByName(const QString &filter)
{
Type type = All;
if (filter == "downloading")
type = Downloading;
else if (filter == "seeding")
type = Seeding;
else if (filter == "completed")
type = Completed;
else if (filter == "paused")
type = Paused;
else if (filter == "resumed")
type = Resumed;
else if (filter == "active")
type = Active;
else if (filter == "inactive")
type = Inactive;
else if (filter == "errored")
type = Errored;
return setType(type);
}
bool TorrentFilter::setHashSet(const QStringSet &hashSet)
{
if (m_hashSet != hashSet) {
m_hashSet = hashSet;
return true;
}
return false;
}
bool TorrentFilter::setLabel(const QString &label)
{
// QString::operator==() doesn't distinguish between empty and null strings.
if ((m_label != label)
|| (m_label.isNull() && !label.isNull())
|| (!m_label.isNull() && label.isNull())) {
m_label = label;
return true;
}
return false;
}
bool TorrentFilter::match(TorrentHandle *const torrent) const
{
if (!torrent) return false;
return (matchState(torrent) && matchHash(torrent) && matchLabel(torrent));
}
bool TorrentFilter::matchState(BitTorrent::TorrentHandle *const torrent) const
{
switch (m_type) {
case All:
return true;
case Downloading:
return torrent->isDownloading();
case Seeding:
return torrent->isUploading();
case Completed:
return torrent->isCompleted();
case Paused:
return torrent->isPaused();
case Resumed:
return torrent->isResumed();
case Active:
return torrent->isActive();
case Inactive:
return torrent->isInactive();
case Errored:
return torrent->isErrored();
default: // All
return true;
}
}
bool TorrentFilter::matchHash(BitTorrent::TorrentHandle *const torrent) const
{
if (m_hashSet == AnyHash) return true;
else return m_hashSet.contains(torrent->hash());
}
bool TorrentFilter::matchLabel(BitTorrent::TorrentHandle *const torrent) const
{
if (m_label.isNull()) return true;
else if (m_label.isEmpty()) return torrent->label().isEmpty();
else return (torrent->label() == m_label);
}

View File

@@ -1,95 +0,0 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2014 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 TORRENTFILTER_H
#define TORRENTFILTER_H
#include <QString>
#include <QSet>
typedef QSet<QString> QStringSet;
namespace BitTorrent
{
class TorrentHandle;
class TorrentState;
}
class TorrentFilter
{
public:
enum Type
{
All,
Downloading,
Seeding,
Completed,
Resumed,
Paused,
Active,
Inactive,
Errored
};
static const QString AnyLabel;
static const QStringSet AnyHash;
static const TorrentFilter DownloadingTorrent;
static const TorrentFilter SeedingTorrent;
static const TorrentFilter CompletedTorrent;
static const TorrentFilter PausedTorrent;
static const TorrentFilter ResumedTorrent;
static const TorrentFilter ActiveTorrent;
static const TorrentFilter InactiveTorrent;
static const TorrentFilter ErroredTorrent;
TorrentFilter();
// label: pass empty string for "no label" or null string (QString()) for "any label"
TorrentFilter(Type type, QStringSet hashSet = AnyHash, QString label = AnyLabel);
TorrentFilter(QString filter, QStringSet hashSet = AnyHash, QString label = AnyLabel);
bool setType(Type type);
bool setTypeByName(const QString &filter);
bool setHashSet(const QStringSet &hashSet);
bool setLabel(const QString &label);
bool match(BitTorrent::TorrentHandle *const torrent) const;
private:
bool matchState(BitTorrent::TorrentHandle *const torrent) const;
bool matchHash(BitTorrent::TorrentHandle *const torrent) const;
bool matchLabel(BitTorrent::TorrentHandle *const torrent) const;
Type m_type;
QString m_label;
QStringSet m_hashSet;
};
#endif // TORRENTFILTER_H

View File

@@ -1,60 +0,0 @@
/*
* 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 "tristatebool.h"
TriStateBool::TriStateBool()
: m_value(Undefined)
{
}
TriStateBool::TriStateBool(bool b)
{
m_value = (b ? True : False);
}
TriStateBool::TriStateBool(TriStateBool::ValueType value)
: m_value(Undefined)
{
switch (value) {
case Undefined:
case True:
case False:
m_value = value;
}
}
TriStateBool::operator bool() const
{
return (m_value == True);
}
TriStateBool::operator ValueType() const
{
return m_value;
}

View File

@@ -1,53 +0,0 @@
/*
* 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 TRISTATEBOOL_H
#define TRISTATEBOOL_H
class TriStateBool
{
public:
enum ValueType
{
Undefined = -1,
False = 0,
True = 1
};
TriStateBool();
TriStateBool(bool b);
TriStateBool(ValueType value);
operator ValueType() const;
operator bool() const;
private:
ValueType m_value;
};
#endif // TRISTATEBOOL_H

View File

@@ -1,74 +0,0 @@
/*
* 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 TYPES_H
#define TYPES_H
#include <QVariant>
#include <QDataStream>
const qlonglong MAX_ETA = 8640000;
enum class MaxRatioAction
{
Pause,
Remove
};
Q_DECLARE_METATYPE(MaxRatioAction)
enum class TorrentExportFolder
{
Regular,
Finished
};
enum class ShutdownAction
{
None,
Shutdown,
Suspend,
Hibernate
};
template<typename T>
inline QDataStream &operator<<(QDataStream &out, const T &val)
{
return (out << static_cast<int>(val));
}
template<typename T>
inline QDataStream &operator>>(QDataStream &in, T &val)
{
int tmp;
in >> tmp;
val = static_cast<T>(tmp);
return in;
}
#endif // TYPES_H

View File

@@ -1,86 +0,0 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Mike Tzou
*
* 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.
*/
// This file must be encoded in "UTF-8 with BOM"
#ifdef _MSC_VER
#pragma execution_character_set("utf-8")
#endif
// Because of the poor handling of UTF-8 characters in MSVC (emits warning C4819),
// we put all problematic UTF-8 chars/strings in this file.
// See issue #3059 for more details (https://github.com/qbittorrent/qBittorrent/issues/3059).
const char C_INFINITY[] = "";
const char C_UP[] = "";
const char C_DOWN[] = "";
const char C_COPYRIGHT[] = "©";
const char C_UTP[] = "μTP";
const char C_LOCALE_ENGLISH[] = "English";
const char C_LOCALE_ENGLISH_AUSTRALIA[] = "English(Australia)";
const char C_LOCALE_ENGLISH_UNITEDKINGDOM[] = "English(United Kingdom)";
const char C_LOCALE_ESPERANTO[] = "Esperanto";
const char C_LOCALE_FRENCH[] = "Français";
const char C_LOCALE_GERMAN[] = "Deutsch";
const char C_LOCALE_HUNGARIAN[] = "Magyar";
const char C_LOCALE_INDONESIAN[] = "Bahasa Indonesia";
const char C_LOCALE_ITALIAN[] = "Italiano";
const char C_LOCALE_DUTCH[] = "Nederlands";
const char C_LOCALE_SPANISH[] = "Español";
const char C_LOCALE_CATALAN[] = "Català";
const char C_LOCALE_GALICIAN[] = "Galego";
const char C_LOCALE_PORTUGUESE[] = "Português";
const char C_LOCALE_PORTUGUESE_BRAZIL[] = "Português brasileiro";
const char C_LOCALE_POLISH[] = "Polski";
const char C_LOCALE_LITHUANIAN[] = "Lietuvių";
const char C_LOCALE_CZECH[] = "Čeština";
const char C_LOCALE_SLOVAK[] = "Slovenčina";
const char C_LOCALE_SLOVENIAN[] = "Slovenščina";
const char C_LOCALE_SERBIAN[] = "Српски";
const char C_LOCALE_CROATIAN[] = "Hrvatski";
const char C_LOCALE_ARMENIAN[] = "Հայերեն";
const char C_LOCALE_ROMANIAN[] = "Română";
const char C_LOCALE_TURKISH[] = "Türkçe";
const char C_LOCALE_GREEK[] = "Ελληνικά";
const char C_LOCALE_SWEDISH[] = "Svenska";
const char C_LOCALE_FINNISH[] = "Suomi";
const char C_LOCALE_NORWEGIAN[] = "Norsk";
const char C_LOCALE_DANISH[] = "Dansk";
const char C_LOCALE_BULGARIAN[] = "Български";
const char C_LOCALE_UKRAINIAN[] = "Українська";
const char C_LOCALE_RUSSIAN[] = "Русский";
const char C_LOCALE_JAPANESE[] = "日本語";
const char C_LOCALE_HEBREW[] = "עברית";
const char C_LOCALE_HINDI[] = "हिन्दी, हिंदी";
const char C_LOCALE_ARABIC[] = "عربي";
const char C_LOCALE_GEORGIAN[] = "ქართული";
const char C_LOCALE_BYELORUSSIAN[] = "Беларуская";
const char C_LOCALE_BASQUE[] = "Euskara";
const char C_LOCALE_VIETNAMESE[] = "tiếng Việt";
const char C_LOCALE_CHINESE_TRADITIONAL_TW[] = "正體中文 (臺灣)";
const char C_LOCALE_CHINESE_TRADITIONAL_HK[] = "繁體中文 (香港)";
const char C_LOCALE_CHINESE_SIMPLIFIED[] = "简体中文";
const char C_LOCALE_KOREAN[] = "한글";

View File

@@ -1,531 +0,0 @@
/*
* Bittorrent Client using Qt 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 <QDebug>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QSettings>
#include <QDirIterator>
#include <QCoreApplication>
#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
#ifndef QBT_USES_QT5
#ifndef DISABLE_GUI
#include <QDesktopServices>
#endif
#else
#include <QStandardPaths>
#endif
#include "misc.h"
#include "fs.h"
/**
* 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 Utils::Fs::toNativePath(const QString& path)
{
return QDir::toNativeSeparators(path);
}
QString Utils::Fs::fromNativePath(const QString &path)
{
return QDir::fromNativeSeparators(path);
}
/**
* Returns the file extension part of a file name.
*/
QString Utils::Fs::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 Utils::Fs::fileName(const QString& file_path)
{
QString path = fromNativePath(file_path);
const int slash_index = path.lastIndexOf("/");
if (slash_index == -1)
return path;
return path.mid(slash_index + 1);
}
QString Utils::Fs::folderName(const QString& file_path)
{
QString path = fromNativePath(file_path);
const int slash_index = path.lastIndexOf("/");
if (slash_index == -1)
return path;
return path.left(slash_index);
}
/**
* This function will first remove system cache files, e.g. `Thumbs.db`,
* `.DS_Store`. Then will try to remove the whole tree if the tree consist
* only of folders
*/
bool Utils::Fs::smartRemoveEmptyFolderTree(const QString& path)
{
if (!QDir(path).exists())
return false;
static const QStringList deleteFilesList = {
// Windows
"Thumbs.db",
"desktop.ini",
// Linux
".directory",
// Mac OS
".DS_Store"
};
// travel from the deepest folder and remove anything unwanted on the way out.
QStringList dirList(path + "/"); // get all sub directories paths
QDirIterator iter(path, (QDir::AllDirs | QDir::NoDotAndDotDot), QDirIterator::Subdirectories);
while (iter.hasNext())
dirList << iter.next() + "/";
std::sort(dirList.begin(), dirList.end(), [](const QString &l, const QString &r) { return l.count("/") > r.count("/"); }); // sort descending by directory depth
for (const QString &p : dirList) {
// remove unwanted files
for (const QString &f : deleteFilesList) {
forceRemove(p + f);
}
// remove temp files on linux (file ends with '~'), e.g. `filename~`
QDir dir(p);
QStringList tmpFileList = dir.entryList(QDir::Files);
for (const QString &f : tmpFileList) {
if (f.endsWith("~"))
forceRemove(p + f);
}
// remove directory if empty
dir.rmdir(p);
}
return QDir(path).exists();
}
/**
* Removes the file with the given file_path.
*
* This function will try to fix the file permissions before removing it.
*/
bool Utils::Fs::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 Utils::Fs::removeDirRecursive(const QString& dirName)
{
#ifdef QBT_USES_QT5
QDir(dirName).removeRecursively();
#else
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);
#endif
}
/**
* 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 Utils::Fs::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 += computePathSize(subfi.absoluteFilePath());
else
size += subfi.size();
}
return size;
}
/**
* Makes deep comparison of two files to make sure they are identical.
*/
bool Utils::Fs::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 Utils::Fs::toValidFileSystemName(const QString &filename)
{
static const QRegExp regex("[\\\\/:?\"*<>|]");
QString validName = filename.trimmed();
validName.replace(regex, " ");
qDebug() << "toValidFileSystemName:" << filename << "=>" << validName;
return validName;
}
bool Utils::Fs::isValidFileSystemName(const QString& filename)
{
if (filename.isEmpty()) return false;
const QRegExp regex("[\\\\/:?\"*<>|]");
return !filename.contains(regex);
}
qlonglong Utils::Fs::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(::GetModuleHandleW(L"kernel32.dll"), "GetDiskFreeSpaceExW");
if (pGetDiskFreeSpaceEx) {
ULARGE_INTEGER bytesFree, bytesTotal;
unsigned long long *ret;
if (pGetDiskFreeSpaceEx((LPCTSTR)(toNativePath(dir_path.path())).utf16(), &bytesFree, &bytesTotal, NULL)) {
ret = (unsigned long long*)&bytesFree;
return *ret;
}
else {
return -1;
}
}
else {
return -1;
}
#endif
}
QString Utils::Fs::branchPath(const QString& file_path, QString* removed)
{
QString ret = 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 Utils::Fs::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 Utils::Fs::expandPath(const QString &path)
{
QString ret = fromNativePath(path.trimmed());
if (ret.isEmpty())
return ret;
return QDir::cleanPath(ret);
}
QString Utils::Fs::expandPathAbs(const QString& path)
{
QString ret = expandPath(path);
if (!QDir::isAbsolutePath(ret))
ret = QDir(ret).absolutePath();
return ret;
}
QString Utils::Fs::QDesktopServicesDataLocation()
{
QString result;
#ifdef Q_OS_WIN
LPWSTR path=new WCHAR[256];
if (SHGetSpecialFolderPath(0, path, CSIDL_LOCAL_APPDATA, FALSE))
result = 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 Utils::Fs::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 Utils::Fs::QDesktopServicesDownloadLocation()
{
#ifdef QBT_USES_QT5
#if defined(Q_OS_WIN)
if (QSysInfo::windowsVersion() <= QSysInfo::WV_XP) // Windows XP
return QDir(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)).absoluteFilePath(
QCoreApplication::translate("fsutils", "Downloads"));
#endif
return QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
#else
#if defined(Q_OS_OS2)
return QDir(QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation)).absoluteFilePath(
QCoreApplication::translate("fsutils", "Downloads"));
#endif
#if defined(Q_OS_WIN)
// 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 (QSysInfo::windowsVersion() <= QSysInfo::WV_XP) // Windows XP
return QDir(QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation)).absoluteFilePath(
QCoreApplication::translate("fsutils", "Downloads"));
else
return QDir(QDesktopServices::storageLocation(QDesktopServices::HomeLocation)).absoluteFilePath("Downloads");
#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
#if defined(Q_OS_MAC)
// TODO: How to support this on Mac OS?
#endif
// Fallback
return QDir::home().absoluteFilePath(QCoreApplication::translate("fsutils", "Downloads"));
#endif
}
QString Utils::Fs::searchEngineLocation()
{
QString folder = "nova";
if (Utils::Misc::pythonVersion() >= 3)
folder = "nova3";
const QString location = expandPathAbs(QDesktopServicesDataLocation() + folder);
QDir locationDir(location);
if (!locationDir.exists())
locationDir.mkpath(locationDir.absolutePath());
return location;
}
QString Utils::Fs::cacheLocation()
{
QString location = expandPathAbs(QDesktopServicesCacheLocation());
QDir locationDir(location);
if (!locationDir.exists())
locationDir.mkpath(locationDir.absolutePath());
return location;
}

View File

@@ -1,142 +0,0 @@
/*
* 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 <QByteArray>
#include <zlib.h>
#include "gzip.h"
bool Utils::Gzip::compress(QByteArray src, QByteArray &dest)
{
static const int BUFSIZE = 128 * 1024;
char tmpBuf[BUFSIZE];
int ret;
dest.clear();
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.next_in = reinterpret_cast<uchar *>(src.data());
strm.avail_in = src.length();
strm.next_out = reinterpret_cast<uchar *>(tmpBuf);
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.append(tmpBuf, BUFSIZE);
strm.next_out = reinterpret_cast<uchar *>(tmpBuf);
strm.avail_out = BUFSIZE;
}
}
int deflateRes = Z_OK;
while (deflateRes == Z_OK) {
if (strm.avail_out == 0) {
dest.append(tmpBuf, BUFSIZE);
strm.next_out = reinterpret_cast<uchar *>(tmpBuf);
strm.avail_out = BUFSIZE;
}
deflateRes = deflate(&strm, Z_FINISH);
}
if (deflateRes != Z_STREAM_END)
return false;
dest.append(tmpBuf, BUFSIZE - strm.avail_out);
deflateEnd(&strm);
return true;
}
bool Utils::Gzip::uncompress(QByteArray src, QByteArray &dest)
{
dest.clear();
if (src.size() <= 4) {
qWarning("uncompress: Input data is truncated");
return false;
}
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 = static_cast<uint>(src.size());
strm.next_in = reinterpret_cast<uchar *>(src.data());
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 false;
// run inflate()
do {
strm.avail_out = CHUNK_SIZE;
strm.next_out = reinterpret_cast<uchar *>(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:
inflateEnd(&strm);
return false;
}
dest.append(out, CHUNK_SIZE - strm.avail_out);
}
while (!strm.avail_out);
// clean up and return
inflateEnd(&strm);
return true;
}

View File

@@ -1,89 +0,0 @@
/*
* 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 UTILS_MISC_H
#define UTILS_MISC_H
#include <vector>
#include <QString>
#include <QStringList>
#include <ctime>
#include <QPoint>
#include <QFile>
#include <QDir>
#include <QUrl>
#include "base/types.h"
/* Miscellaneous functions that can be useful */
namespace Utils
{
namespace Misc
{
QString parseHtmlLinks(const QString &raw_text);
bool isUrl(const QString &s);
#ifndef DISABLE_GUI
void shutdownComputer(ShutdownAction action);
// Get screen center
QPoint screenCenter(QWidget *win);
QSize smallIconSize();
#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 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);
#ifndef DISABLE_GUI
void openPath(const QString& absolutePath);
void openFolderSelect(const QString& absolutePath);
#endif
void msleep(unsigned long msecs);
}
}
#endif

View File

@@ -1,211 +0,0 @@
/*
* 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 <QByteArray>
#include <QString>
#include <QLocale>
#include <cmath>
#include "string.h"
QString Utils::String::fromStdString(const std::string &str)
{
return QString::fromUtf8(str.c_str());
}
std::string Utils::String::toStdString(const QString &str)
{
QByteArray utf8 = str.toUtf8();
return std::string(utf8.constData(), utf8.length());
}
// uses lessThan comparison
bool Utils::String::naturalSort(const QString &left, const QString &right, bool &result)
{
// Return value indicates if functions was successful
// result argument will contain actual comparison result if function was successful
int posL = 0;
int posR = 0;
do {
forever {
if (posL == left.size() || posR == right.size())
return false; // No data
QChar leftChar = left.at(posL);
QChar rightChar = right.at(posR);
bool leftCharIsDigit = leftChar.isDigit();
bool rightCharIsDigit = rightChar.isDigit();
if (leftCharIsDigit != rightCharIsDigit)
return false; // Digit positions mismatch
if (leftCharIsDigit)
break; // Both are digit, break this loop and compare numbers
if (leftChar != rightChar)
return false; // Strings' subsets before digit do not match
++posL;
++posR;
}
QString temp;
while (posL < left.size()) {
if (left.at(posL).isDigit())
temp += left.at(posL);
else
break;
posL++;
}
int numL = temp.toInt();
temp.clear();
while (posR < right.size()) {
if (right.at(posR).isDigit())
temp += right.at(posR);
else
break;
posR++;
}
int numR = temp.toInt();
if (numL != numR) {
result = (numL < numR);
return true;
}
// Strings + digits do match and we haven't hit string end
// Do another round
} while (true);
return false;
}
Utils::String::NaturalCompare::NaturalCompare()
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
#if defined(Q_OS_WIN)
// Without ICU library, QCollator doesn't support `setNumericMode(true)` on OS older than Win7
if(QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS7)
return;
#endif
m_collator.setNumericMode(true);
m_collator.setCaseSensitivity(Qt::CaseInsensitive);
#endif
}
bool Utils::String::NaturalCompare::operator()(const QString &l, const QString &r)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
#if defined(Q_OS_WIN)
// Without ICU library, QCollator doesn't support `setNumericMode(true)` on OS older than Win7
if(QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS7)
return lessThan(l, r);
#endif
return (m_collator.compare(l, r) < 0);
#else
return lessThan(l, r);
#endif
}
bool Utils::String::NaturalCompare::lessThan(const QString &left, const QString &right)
{
// Return value `false` indicates `right` should go before `left`, otherwise, after
int posL = 0;
int posR = 0;
while (true) {
while (true) {
if (posL == left.size() || posR == right.size())
return (left.size() < right.size()); // when a shorter string is another string's prefix, shorter string place before longer string
QChar leftChar = left[posL].toLower();
QChar rightChar = right[posR].toLower();
if (leftChar == rightChar)
; // compare next character
else if (leftChar.isDigit() && rightChar.isDigit())
break; // Both are digits, break this loop and compare numbers
else
return leftChar < rightChar;
++posL;
++posR;
}
int startL = posL;
while ((posL < left.size()) && left[posL].isDigit())
++posL;
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
int numL = left.midRef(startL, posL - startL).toInt();
#else
int numL = left.mid(startL, posL - startL).toInt();
#endif
int startR = posR;
while ((posR < right.size()) && right[posR].isDigit())
++posR;
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
int numR = right.midRef(startR, posR - startR).toInt();
#else
int numR = right.mid(startR, posR - startR).toInt();
#endif
if (numL != numR)
return (numL < numR);
// Strings + digits do match and we haven't hit string end
// Do another round
}
return false;
}
// to send numbers instead of strings with suffixes
QString Utils::String::fromDouble(double n, int precision)
{
/* HACK because QString rounds up. Eg QString::number(0.999*100.0, 'f' ,1) == 99.9
** but QString::number(0.9999*100.0, 'f' ,1) == 100.0 The problem manifests when
** the number has more digits after the decimal than we want AND the digit after
** our 'wanted' is >= 5. In this case our last digit gets rounded up. So for each
** precision we add an extra 0 behind 1 in the below algorithm. */
double prec = std::pow(10.0, precision);
return QLocale::system().toString(std::floor(n * prec) / prec, 'f', precision);
}
// Implements constant-time comparison to protect against timing attacks
// Taken from https://crackstation.net/hashing-security.htm
bool Utils::String::slowEquals(const QByteArray &a, const QByteArray &b)
{
int lengthA = a.length();
int lengthB = b.length();
int diff = lengthA ^ lengthB;
for (int i = 0; (i < lengthA) && (i < lengthB); i++)
diff |= a[i] ^ b[i];
return (diff == 0);
}

View File

@@ -1,70 +0,0 @@
/*
* 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 UTILS_STRING_H
#define UTILS_STRING_H
#include <string>
#include <QtGlobal>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
#include <QCollator>
#endif
class QString;
class QByteArray;
namespace Utils
{
namespace String
{
QString fromStdString(const std::string &str);
std::string toStdString(const QString &str);
QString fromDouble(double n, int precision);
// 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);
bool naturalSort(const QString &left, const QString &right, bool &result);
class NaturalCompare
{
public:
NaturalCompare();
bool operator()(const QString &l, const QString &r);
bool lessThan(const QString &left, const QString &right);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
private:
QCollator m_collator;
#endif
};
}
}
#endif // UTILS_STRING_H

43
src/core/core.pri Normal file
View File

@@ -0,0 +1,43 @@
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/filesystemwatcher.h \
$$PWD/scannedfoldersmodel.h \
$$PWD/qinisettings.h \
$$PWD/smtp.h \
$$PWD/dnsupdater.h \
$$PWD/logger.h \
$$PWD/preferences.h \
$$PWD/qtracker.h \
$$PWD/http/irequesthandler.h \
$$PWD/http/connection.h \
$$PWD/http/requestparser.h \
$$PWD/http/responsegenerator.h \
$$PWD/http/server.h \
$$PWD/http/types.h \
$$PWD/http/responsebuilder.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/logger.cpp \
$$PWD/preferences.cpp \
$$PWD/qtracker.cpp \
$$PWD/http/connection.cpp \
$$PWD/http/requestparser.cpp \
$$PWD/http/responsegenerator.cpp \
$$PWD/http/server.cpp \
$$PWD/http/responsebuilder.cpp

297
src/core/dnsupdater.cpp Normal file
View File

@@ -0,0 +1,297 @@
/*
* 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" chris@qbittorrent.org");
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" chris@qbittorrent.org");
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

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

312
src/core/downloadthread.cpp Normal file
View File

@@ -0,0 +1,312 @@
/*
* 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 3.5 user agent to avoid
// Web server banning
request.setRawHeader("User-Agent", "Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5");
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

77
src/core/downloadthread.h Normal file
View File

@@ -0,0 +1,77 @@
/*
* 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 DOWNLOADTHREAD_H
#define DOWNLOADTHREAD_H
#include <QNetworkReply>
#include <QNetworkCookie>
#include <QObject>
#include <QHash>
#include <QSslError>
#include <zlib.h>
QT_BEGIN_NAMESPACE
class QNetworkAccessManager;
QT_END_NAMESPACE
class DownloadThread : public QObject {
Q_OBJECT
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);
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);
private slots:
void processDlFinished(QNetworkReply* reply);
void checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal);
#ifndef QT_NO_OPENSSL
void ignoreSslErrors(QNetworkReply*,const QList<QSslError>&);
#endif
private:
static QByteArray gUncompress(Bytef *inData, size_t len);
QString errorCodeToString(QNetworkReply::NetworkError status);
void applyProxySettings();
private:
QNetworkAccessManager m_networkManager;
QHash<QString, QString> m_redirectMapping;
};
#endif

View File

@@ -0,0 +1,297 @@
#ifndef FILESYSTEMWATCHER_H
#define FILESYSTEMWATCHER_H
#include <QFileSystemWatcher>
#include <QDir>
#include <QTimer>
#include <QPointer>
#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
public:
FileSystemWatcher(QObject *parent): QFileSystemWatcher(parent) {
m_filters << "*.torrent" << "*.magnet";
connect(this, SIGNAL(directoryChanged(QString)), this, SLOT(scanLocalFolder(QString)));
}
~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);
}
signals:
void torrentsAdded(QStringList &pathList);
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();
}
};
#endif // FILESYSTEMWATCHER_H

531
src/core/fs_utils.cpp Normal file
View File

@@ -0,0 +1,531 @@
/*
* 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();
}
/**
* 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,5 +1,5 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2012 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
@@ -28,46 +28,46 @@
* Contact : chris@qbittorrent.org
*/
#ifndef UTILS_FS_H
#define UTILS_FS_H
#ifndef FS_UTILS_H
#define FS_UTILS_H
#include <QString>
/**
* Utility functions related to file system.
*/
#include <QString>
namespace Utils
namespace fsutils
{
namespace Fs
{
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 toValidFileSystemName(const QString &filename);
bool isValidFileSystemName(const QString& filename);
qlonglong 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 smartRemoveEmptyFolderTree(const QString& path);
bool forceRemove(const QString& file_path);
void removeDirRecursive(const QString& dirName);
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);
/* Ported from Qt4 to drop dependency on QtGui */
QString QDesktopServicesDataLocation();
QString QDesktopServicesCacheLocation();
QString QDesktopServicesDownloadLocation();
/* End of Qt4 code */
QString searchEngineLocation();
QString BTBackupLocation();
QString cacheLocation();
/* Ported from Qt4 to drop dependency on QtGui */
QString QDesktopServicesDataLocation();
QString QDesktopServicesCacheLocation();
QString QDesktopServicesDownloadLocation();
/* End of Qt4 code */
QString searchEngineLocation();
QString cacheLocation();
}
}
#endif // UTILS_FS_H
#endif // FS_UTILS_H

View File

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

View File

@@ -33,12 +33,14 @@
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

@@ -31,7 +31,7 @@
#include <QStringList>
#include <QUrl>
#ifdef QBT_USES_QT5
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
#include <QUrlQuery>
#endif
#include <QDir>
@@ -79,8 +79,9 @@ RequestParser::ErrorCode RequestParser::parseHttpRequest(const QByteArray& data,
}
// Parse HTTP request message
int content_length = 0;
if (m_request.headers.contains("content-length")) {
int content_length = m_request.headers["content-length"].toInt();
content_length = m_request.headers["content-length"].toInt();
if (content_length > static_cast<int>(m_maxContentLength)) {
qWarning() << Q_FUNC_INFO << "bad request: message too long";
return BadRequest;
@@ -117,7 +118,7 @@ bool RequestParser::parseStartingLine(const QString &line)
m_request.path = url.path(); // Path
// Parse GET parameters
#ifndef QBT_USES_QT5
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
QListIterator<QPair<QString, QString> > i(url.queryItems());
#else
QListIterator<QPair<QString, QString> > i(QUrlQuery(url).queryItems());
@@ -216,7 +217,7 @@ bool RequestParser::parseContent(const QByteArray& data)
// Parse url-encoded POST data
if (m_request.headers["content-type"].startsWith("application/x-www-form-urlencoded")) {
QUrl url;
#ifndef QBT_USES_QT5
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
url.setEncodedQuery(data);
QListIterator<QPair<QString, QString> > i(url.queryItems());
#else
@@ -330,22 +331,16 @@ bool RequestParser::parseFormData(const QByteArray& data)
bool RequestParser::parseHeaderValue(const QString& value, QStringMap& out)
{
int pos = value.indexOf(QLatin1Char(';'));
if (pos == -1) {
out[""] = value.trimmed();
return true;
QStringList items = value.split(QLatin1Char(';'));
out[""] = items[0];
for (QStringList::size_type i = 1; i < items.size(); ++i) {
int pos = items[i].indexOf("=");
if (pos < 0)
return false;
out[items[i].left(pos).trimmed()] = unquoted(items[i].mid(pos + 1).trimmed());
}
out[""] = value.left(pos).trimmed();
QRegExp rx(";\\s*([^=;\"]+)\\s*=\\s*(\"[^\"]*\"|[^\";\\s]+)\\s*");
while (rx.indexIn(value, pos) == pos) {
out[rx.cap(1).trimmed()] = unquoted(rx.cap(2));
pos += rx.cap(0).length();
}
if (pos != value.length())
return false;
return true;
}

View File

@@ -36,37 +36,39 @@
namespace Http
{
class RequestParser
class RequestParser
{
public:
enum ErrorCode
{
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;
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;
};
}
#endif // HTTP_REQUESTPARSER_H

View File

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

View File

@@ -29,9 +29,11 @@
* Contact : chris@qbittorrent.org
*/
#include "base/utils/gzip.h"
#include <zlib.h>
#include "responsegenerator.h"
bool gCompress(QByteArray data, QByteArray& dest_buffer);
using namespace Http;
QByteArray ResponseGenerator::generate(Response response)
@@ -42,7 +44,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) && (Utils::Gzip::compress(response.content, dest_buf)))
if ((response.content.size() > 49) && (gCompress(response.content, dest_buf)))
response.content = dest_buf;
else
response.headers.remove(HEADER_CONTENT_ENCODING);
@@ -65,3 +67,58 @@ 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,11 +37,13 @@
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
@@ -67,7 +67,7 @@ void Server::disableHttps()
}
#endif
#ifdef QBT_USES_QT5
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
void Server::incomingConnection(qintptr socketDescriptor)
#else
void Server::incomingConnection(int socketDescriptor)

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