Compare commits

...

54 Commits

Author SHA1 Message Date
sledgehammer999
5876886345 Bump to 4.3.1 2020-11-25 13:49:50 +02:00
sledgehammer999
0392bfce3c Update Changelog 2020-11-25 13:49:48 +02:00
sledgehammer999
c66cf43d6a Sync translations from Transifex and run lupdate 2020-11-24 17:04:07 +02:00
Chocobo1
7515afc058 Pin github actions scripts to major versions
> Using the specific major action version allows you to receive critical
> fixes and security patches while still maintaining compatibility. It
> also assures that your workflow should still work.
https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsuses
2020-11-24 16:14:16 +02:00
Thomas De Rocker
5fcfcc901e Fix confusion in date format description (#1)
* Update automatedrssdownloader.ui

* Update rssDownloader.html (#2)
2020-11-24 16:14:15 +02:00
Vladimir Golovnev (Glassez)
1728c16580 Improve coding style 2020-11-24 16:14:14 +02:00
Thomas De Rocker
d3f46452a9 Update dutch.nsi
As referenced in https://github.com/qbittorrent/qBittorrent/pull/13615
and suggested by @glassez 
- Use the word qBittorrent when it is mentioned for the first time within a string.
- If the string contains other references to qBittorrent, then use it (rather than repeating qBittorrent).

Line 24 is the updated Dutch translation for the recently updated English source string (may 2020)
2020-11-24 16:14:09 +02:00
sledgehammer999
7092a98c93 Add Latgalian translation
Closes #12415
2020-11-24 16:14:08 +02:00
sledgehammer999
8e19f66b4f Update .desktop file translations 2020-11-24 16:14:06 +02:00
Chocobo1
b6ab2abf3f Don't use deprecated torrent state "allocating"
Closes #13737.
2020-11-24 16:14:05 +02:00
Vladimir Golovnev (Glassez)
3edaaa30c9 Handle torrent "paused" state at application level 2020-11-24 16:14:04 +02:00
FranciscoPombal
38efff461e Add GitHub Actions file health workflow 2020-11-24 16:14:03 +02:00
FranciscoPombal
2179148b8d Make sure there are no empty files 2020-11-24 16:14:02 +02:00
FranciscoPombal
f92c4c0a40 Fix extra/missing trailing new lines in files 2020-11-24 16:14:00 +02:00
FranciscoPombal
1e7f792dbb Fix trailing whitespace in multiple files
Also fix formatting of CODING_GUIDELINES.md
2020-11-24 16:13:59 +02:00
FranciscoPombal
1d4af505c2 Encode files in UTF-8 without BOM 2020-11-24 16:13:57 +02:00
Chocobo1
baa609b713 Remove unused function 2020-11-24 16:13:55 +02:00
Chocobo1
bc20cf9ad7 Remove redundant semicolon 2020-11-24 16:13:53 +02:00
Chocobo1
7d3ecfa9a6 Allow adding torrents using "Paste" key sequence
Closes #13685.
2020-11-24 16:13:52 +02:00
NotTsunami
88a90ed7d4 Fix mingw64 build error
mingw64 defines interface, so revert back to previous naming scheme

Fixes: 87864531ab
Closes #13649
2020-11-24 16:13:51 +02:00
jagannatharjun
3e540b3f51 Align integer data to right in torrent content view 2020-11-24 16:13:50 +02:00
jagannatharjun
87e1661bd5 Rename TR_PROGRESS header in TransferList
Closes #13665
2020-11-24 16:13:49 +02:00
Chocobo1
f82a4051af Remove outdated information 2020-11-24 16:13:47 +02:00
Vladimir Golovnev (Glassez)
5730e917a1 Fix torrent state calculation 2020-11-24 16:13:46 +02:00
Vladimir Golovnev (Glassez)
5e7d7c2ef0 Don't resume "paused" torrents when checking by libtorrent 2020-11-24 16:13:45 +02:00
jagannatharjun
2b6e1953d7 Use ProgressbarDelegate for drawing progressbar in PropListDelegate
Also directly provide display data from model rather then generating it in delegate
2020-11-24 16:13:43 +02:00
jagannatharjun
6fc50f4169 Use ProgressBarDelegate for drawing progressbar in TransferListView 2020-11-24 16:13:42 +02:00
jagannatharjun
40d7a53695 Implement ProgressBarDelegate 2020-11-24 16:13:41 +02:00
Chocobo1
7e89893454 Add support for tracker scrape in libtorrent 2.0 2020-11-24 16:13:39 +02:00
Chocobo1
d83f09e731 Migrate away from deprecated functions in libtorrent 2.0 2020-11-24 16:13:38 +02:00
Chocobo1
36575b225d Improve compatibility with libtorrent 2.0
In libtorrent 2.0, the `connection_type` was changed to a flag type and
hence it cannot be used in a switch statement directly. Also our use of
`connection_type` is limited so that a single equality comparison
would cover all of our use cases.
2020-11-24 16:13:36 +02:00
jagannatharjun
fe0ea843e0 Fix crash when clicked outside the table of torrent content view
Closes #13645
2020-11-24 16:13:35 +02:00
FranciscoPombal
a8911f8136 Clarify protocol choice label 2020-11-24 16:13:34 +02:00
FranciscoPombal
c5ef1a0207 Update "GitHub Actions" CI actions versions 2020-11-24 16:13:32 +02:00
brvphoenix
102d628c0a Fix the issue that IPv6 address can't be banned
The ban action doesn't depend on ipfilter.
2020-11-24 16:13:31 +02:00
FranciscoPombal
6ea3acdaea Expose contentPath in WebAPI torrents/info
Bump WebAPI version to 2.6.1
2020-11-24 16:13:30 +02:00
Chocobo1
621578353d Remove redundant checking before remove 2020-11-24 16:13:29 +02:00
Chocobo1
ca776c3036 Fix class name 2020-11-24 16:13:28 +02:00
Chocobo1
9d27eb3b57 Move qHash helper for libtorrent types to its own file 2020-11-24 16:13:26 +02:00
Vladimir Golovnev (Glassez)
9171dffe97 Prevent resume data to be saved for removed torrent 2020-11-24 16:13:25 +02:00
thalieht
f919d4f5bf Fix toggling advanced option in WebUI
option "Disallow connection to peers on privileged ports"
2020-11-24 16:13:24 +02:00
Chocobo1
59afc7c520 Avoid settings being reset via WebAPI
Closes #13585.
2020-11-24 16:13:23 +02:00
Chocobo1
f02b65b866 Fix typos 2020-11-24 16:13:19 +02:00
Andrei Stepanov
891c471160 Fix typo in connection.cpp
limiation -> limitation
2020-11-24 16:13:17 +02:00
Sepro
f49f5ba9a1 Place WebUI RSS description in sandboxed iframe 2020-11-24 16:10:40 +02:00
NotTsunami
539b3b7c3e Remove branches block from Travis config
This block has no significance because these branches are stale and
builds will not be triggered on these branches.
2020-11-24 16:10:39 +02:00
NotTsunami
83ce285138 Disallow CMake build failures on Travis
Our CMake configuration has matured over time, thus require CMake
builds to require successful builds on Travis CI.
2020-11-24 16:10:30 +02:00
sledgehammer999
260e48b705 Correct the Changelog entry 2020-10-22 14:48:11 +03:00
sledgehammer999
f09ee1b398 Bump to 4.3.0.1 2020-10-22 09:29:00 +03:00
sledgehammer999
e3c2266611 Update Changelog 2020-10-22 09:22:54 +03:00
bovirus
53fb6220c5 NSIS: Update Italian translation 2020-10-22 09:21:00 +03:00
sledgehammer999
34e6b73374 Close parentheses in Changelog entry 2020-10-19 01:48:52 +03:00
sledgehammer999
b925cffddb Bump to 4.3.0 2020-10-18 22:41:04 +03:00
sledgehammer999
3595626eff Update Changelog 2020-10-18 22:41:03 +03:00
378 changed files with 96326 additions and 82880 deletions

View File

@@ -17,4 +17,3 @@
### Extra info(if any) ### Extra info(if any)
(type here) (type here)

View File

@@ -17,7 +17,7 @@ env:
VCPKG_COMMIT: 32eccc18191fbb57b159784a1724d2d00613ae82 VCPKG_COMMIT: 32eccc18191fbb57b159784a1724d2d00613ae82
VCPKG_DEST_MACOS: /Users/runner/qbt_tools/vcpkg VCPKG_DEST_MACOS: /Users/runner/qbt_tools/vcpkg
VCPKG_DEST_WIN: C:\qbt_tools\vcpkg VCPKG_DEST_WIN: C:\qbt_tools\vcpkg
UBUNTU_LIBTORRENT_VERSION: libtorrent-1.2.10 LIBTORRENT_VERSION_TAG: libtorrent-1.2.10
jobs: jobs:
@@ -38,7 +38,7 @@ jobs:
steps: steps:
- name: checkout repository - name: checkout repository
uses: actions/checkout@v2.3.2 uses: actions/checkout@v2
- name: install all build dependencies except libtorrent from Ubuntu repos - name: install all build dependencies except libtorrent from Ubuntu repos
run: | run: |
@@ -52,7 +52,7 @@ jobs:
- name: install libtorrent from source - name: install libtorrent from source
run: | run: |
git clone https://github.com/arvidn/libtorrent && cd libtorrent git clone https://github.com/arvidn/libtorrent && cd libtorrent
git checkout ${{ env.UBUNTU_LIBTORRENT_VERSION }} git checkout ${{ env.LIBTORRENT_VERSION_TAG }}
cmake -B cmake-build-dir -G "Ninja" \ cmake -B cmake-build-dir -G "Ninja" \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo \
-Ddeprecated-functions=OFF \ -Ddeprecated-functions=OFF \
@@ -70,7 +70,7 @@ jobs:
cmake --build build cmake --build build
- name: upload artifact as zip - name: upload artifact as zip
uses: actions/upload-artifact@v2.1.3 uses: actions/upload-artifact@v2
with: with:
name: qBittorrent-CI-Ubuntu_${{ matrix.os }}-${{ matrix.qbt_gui }} name: qBittorrent-CI-Ubuntu_${{ matrix.os }}-${{ matrix.qbt_gui }}
path: | path: |
@@ -92,7 +92,7 @@ jobs:
steps: steps:
- name: checkout repository - name: checkout repository
uses: actions/checkout@v2.3.2 uses: actions/checkout@v2
# - ninja is needed for building qBittorrent (because it's preferrable, not a hard requirement) # - ninja is needed for building qBittorrent (because it's preferrable, not a hard requirement)
- name: install additional required packages with chocolatey - name: install additional required packages with chocolatey
@@ -100,7 +100,7 @@ jobs:
choco install ninja choco install ninja
- name: setup vcpkg (cached, if possible) - name: setup vcpkg (cached, if possible)
uses: lukka/run-vcpkg@v3.3 uses: lukka/run-vcpkg@v4
with: with:
vcpkgDirectory: ${{ env.VCPKG_DEST_WIN }} vcpkgDirectory: ${{ env.VCPKG_DEST_WIN }}
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT }} vcpkgGitCommitId: ${{ env.VCPKG_COMMIT }}
@@ -134,7 +134,7 @@ jobs:
# NOTE: this is necessary to correctly find and use cl.exe with the Ninja generator for now # NOTE: this is necessary to correctly find and use cl.exe with the Ninja generator for now
- name: setup devcmd - name: setup devcmd
uses: ilammy/msvc-dev-cmd@v1.3.0 uses: ilammy/msvc-dev-cmd@v1
- name: build qBittorrent - name: build qBittorrent
shell: cmd shell: cmd
@@ -149,7 +149,7 @@ jobs:
cmake --build build cmake --build build
- name: upload artifact as zip - name: upload artifact as zip
uses: actions/upload-artifact@v2.1.3 uses: actions/upload-artifact@v2
with: with:
name: qBittorrent-CI-Windows_x64-static-release name: qBittorrent-CI-Windows_x64-static-release
path: | path: |
@@ -175,7 +175,7 @@ jobs:
steps: steps:
- name: checkout repository - name: checkout repository
uses: actions/checkout@v2.3.2 uses: actions/checkout@v2
# - ninja is needed for building qBittorrent (because it's preferrable, not a hard requirement) # - ninja is needed for building qBittorrent (because it's preferrable, not a hard requirement)
# - pkg-config is needed for some vcpkg installations # - pkg-config is needed for some vcpkg installations
@@ -185,7 +185,7 @@ jobs:
brew install ninja pkg-config brew install ninja pkg-config
- name: setup vcpkg (cached, if possible) - name: setup vcpkg (cached, if possible)
uses: lukka/run-vcpkg@v3.3 uses: lukka/run-vcpkg@v4
with: with:
vcpkgDirectory: ${{ env.VCPKG_DEST_MACOS }} vcpkgDirectory: ${{ env.VCPKG_DEST_MACOS }}
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT }} vcpkgGitCommitId: ${{ env.VCPKG_COMMIT }}
@@ -234,7 +234,7 @@ jobs:
cmake --build build cmake --build build
- name: upload artifact as zip - name: upload artifact as zip
uses: actions/upload-artifact@v2.1.3 uses: actions/upload-artifact@v2
with: with:
name: qBittorrent-CI-macOS_x64-static-release_${{ matrix.qbt_gui }} name: qBittorrent-CI-macOS_x64-static-release_${{ matrix.qbt_gui }}
path: | path: |

75
.github/workflows/file_health.sh vendored Executable file
View File

@@ -0,0 +1,75 @@
#!/usr/bin/env zsh
set -o nounset
# Assumption: file names don't contain `:` (for the `cut` invocation).
# Safe to assume, as such a character in a filename would cause trouble on Windows, a platform we support
# any regression turn this non-zero
regressions=0
# exclusions (these are just grep extended regular expressions to match against paths relative to the root of the repository)
exclusions_nonutf8='(.*(7z|gif|ic(ns|o)|png|qm|zip))'
exclusions_bom='src/base/unicodestrings.h'
exclusions_tw='(*.ts)|src/webui/www/private/scripts/lib/mootools-1.2-more.js'
exclusions_no_lf='(*.ts)|(.*svg)|compile_commands.json|src/webui/www/private/scripts/lib/mootools-1.2-(core-yc.js|more.js)'
echo -e "*** Detect files not encoded in UTF-8 ***\n"
find . -path ./build -prune -false -o -path ./.git -prune -false -o -type f -exec file --mime {} \; | sort \
| grep -v -e "charset=us-ascii" -e "charset=utf-8" | cut -d ":" -f 1 \
| grep -E -v -e "${exclusions_nonutf8}" \
| tee >(echo -e "\n--> Files not encoded in UTF-8: found" "$(wc -l < /dev/stdin)" "regression(s)") \
| xargs -I my_input -0 bash -c 'echo "my_input"; test "$(echo -n "my_input" | wc -l)" -eq 0'
regressions=$((regressions+$?))
echo -e "*** Detect files encoded in UTF-8 with BOM ***\n"
grep --exclude-dir={.git,build} -rIl $'\xEF\xBB\xBF' | sort \
| grep -E -v -e "${exclusions_bom}" \
| tee >(echo -e "\n--> Files encoded in UTF-8 with BOM: found" "$(wc -l < /dev/stdin)" "regression(s)") \
| xargs -I my_input -0 bash -c 'echo "my_input"; test "$(echo -n "my_input" | wc -l)" -eq 0'
regressions=$((regressions+$?))
echo -e "*** Detect usage of CR byte ***\n"
grep --exclude-dir={.git,build} -rIlU $'\x0D' | sort \
| tee >(echo -e "\n--> Usage of CR byte: found" "$(wc -l < /dev/stdin)" "regression(s)") \
| xargs -I my_input -0 bash -c 'echo "my_input"; test "$(echo -n "my_input" | wc -l)" -eq 0'
regressions=$((regressions+$?))
echo -e "*** Detect trailing whitespace in lines ***\n"
grep --exclude-dir={.git,build} -rIl "[[:blank:]]$" | sort \
| grep -E -v -e "${exclusions_tw}" \
| tee >(echo -e "\n--> Trailing whitespace in lines: found" "$(wc -l < /dev/stdin)" "regression(s)") \
| xargs -I my_input -0 bash -c 'echo "my_input"; test "$(echo -n "my_input" | wc -l)" -eq 0';
regressions=$((regressions+$?))
echo -e "*** Detect too many trailing newlines ***\n"
find . -path ./build -prune -false -o -path ./.git -prune -false -o -type f -exec file --mime {} \; | sort \
| grep -e "charset=us-ascii" -e "charset=utf-8" | cut -d ":" -f 1 \
| xargs -L1 -I my_input bash -c 'test "$(tail -q -c2 "my_input" | hexdump -C | grep "0a 0a")" && echo "my_input"' \
| tee >(echo -e "\n--> Too many trailing newlines: found" "$(wc -l < /dev/stdin)" "regression(s)") \
| xargs -I my_input -0 bash -c 'echo "my_input"; test "$(echo -n "my_input" | wc -l)" -eq 0'
regressions=$((regressions+$?))
echo -e "*** Detect no trailing newline ***\n"
find . -path ./build -prune -false -o -path ./.git -prune -false -o -type f -exec file --mime {} \; | sort \
| grep -e "charset=us-ascii" -e "charset=utf-8" | cut -d ":" -f 1 \
| grep -E -v -e "${exclusions_no_lf}" \
| xargs -L1 -I my_input bash -c 'test "$(tail -q -c1 "my_input" | hexdump -C | grep "0a")" || echo "my_input"' \
| tee >(echo -e "\n--> No trailing newline: found" "$(wc -l < /dev/stdin)" "regression(s)") \
| xargs -I my_input -0 bash -c 'echo "my_input"; test "$(echo -n "my_input" | wc -l)" -eq 0'
regressions=$((regressions+$?))
if [ "$regressions" -ne 0 ]; then
regressions=1
echo "File health regressions found. Please fix them (or add them as exclusions)."
else
echo "All OK, no file health regressions found."
fi
exit $regressions;

27
.github/workflows/file_health.yaml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: GitHub Actions file health check
on:
push:
branches: [ '**' ]
pull_request:
types: [edited, opened, reopened, synchronize]
branches: [ '**' ]
jobs:
check_file_health:
name: Check file health
runs-on: ubuntu-latest
steps:
- name: checkout repository
uses: actions/checkout@v2
- name: install zsh
run: |
sudo apt update
sudo apt install zsh
- name: run check file health script
run: |
./.github/workflows/file_health.sh

View File

@@ -16,16 +16,6 @@ env:
- secure: "OI9CUjj4lTb0HwwIZU5PbECU3hLlAL6KC8KsbwohG8/O3j5fLcnmDsK4Ad9us5cC39sS11Jcd1kDP2qRcCuST/glVNhLkcjKkiQerOfd5nQ/qL4JYfz/1mfP5mdpz9jHKzpLUIG+TXkbSTjP6VVmsb5KPT+3pKEdRFZB+Pu9+J8=" - secure: "OI9CUjj4lTb0HwwIZU5PbECU3hLlAL6KC8KsbwohG8/O3j5fLcnmDsK4Ad9us5cC39sS11Jcd1kDP2qRcCuST/glVNhLkcjKkiQerOfd5nQ/qL4JYfz/1mfP5mdpz9jHKzpLUIG+TXkbSTjP6VVmsb5KPT+3pKEdRFZB+Pu9+J8="
- coverity_branch: coverity_scan - coverity_branch: coverity_scan
matrix:
allow_failures:
- env: libt_branch=RC_1_2 gui=true build_system=cmake
- env: libt_branch=RC_1_2 gui=false build_system=cmake
branches:
except:
- search_encoding_windows
- v2_9_x
notifications: notifications:
email: email:
on_success: change on_success: change

View File

@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.16 FATAL_ERROR) # Policies <= CMP0097 default t
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules)
project(qBittorrent project(qBittorrent
VERSION 4.3.0.0 VERSION 4.3.1.0
DESCRIPTION "The qBittorrent BitTorrent client" DESCRIPTION "The qBittorrent BitTorrent client"
HOMEPAGE_URL "https://www.qbittorrent.org/" HOMEPAGE_URL "https://www.qbittorrent.org/"
LANGUAGES CXX LANGUAGES CXX

View File

@@ -1,12 +1,14 @@
All new code **must** follow the following coding guidelines. # Coding Guidelines
If you make changes in a file that still uses another coding style, make sure that you follow these guidelines for your changes.
All new code **must** follow the following coding guidelines. \
If you make changes in a file that still uses another coding style, make sure that you follow these guidelines for your changes. \
For programming languages other than C++ (e.g. JavaScript) used in this repository and submodules, unless otherwise specified, coding guidelines listed here applies as much as possible. For programming languages other than C++ (e.g. JavaScript) used in this repository and submodules, unless otherwise specified, coding guidelines listed here applies as much as possible.
**Note 1:** I will not take your head if you forget and use another style. However, most probably the request will be delayed until you fix your coding style. **Note 1:** I will not take your head if you forget and use another style. However, most probably the request will be delayed until you fix your coding style. \
**Note 2:** You can use the `uncrustify` program/tool to clean up any source file. Use it with the `uncrustify.cfg` configuration file found in the root folder. **Note 2:** You can use the `uncrustify` program/tool to clean up any source file. Use it with the `uncrustify.cfg` configuration file found in the root folder. \
**Note 3:** There is also a style for QtCreator but it doesn't cover all cases. In QtCreator `Tools->Options...->C++->Code Style->Import...` and choose the `codingStyleQtCreator.xml` file found in the root folder. **Note 3:** There is also a style for QtCreator but it doesn't cover all cases. In QtCreator `Tools->Options...->C++->Code Style->Import...` and choose the `codingStyleQtCreator.xml` file found in the root folder.
### Table Of Contents ## Table Of Contents
* [1. New lines &amp; curly braces](#1-new-lines--curly-braces) * [1. New lines &amp; curly braces](#1-new-lines--curly-braces)
* [a. Function blocks, class/struct definitions, namespaces](#a-function-blocks-classstruct-definitions-namespaces) * [a. Function blocks, class/struct definitions, namespaces](#a-function-blocks-classstruct-definitions-namespaces)
@@ -29,11 +31,13 @@ For programming languages other than C++ (e.g. JavaScript) used in this reposito
* [9. Misc](#9-misc) * [9. Misc](#9-misc)
* [10. Git commit message](#10-git-commit-message) * [10. Git commit message](#10-git-commit-message)
* [11. Not covered above](#11-not-covered-above) * [11. Not covered above](#11-not-covered-above)
--- ---
### 1. New lines & curly braces ### ## 1. New lines & curly braces
### a. Function blocks, class/struct definitions, namespaces
#### a. Function blocks, class/struct definitions, namespaces ####
```c++ ```c++
int myFunction(int a) int myFunction(int a)
{ {
@@ -43,7 +47,7 @@ int myFunction(int a)
void myFunction() {} // empty body void myFunction() {} // empty body
MyClass::MyClass(int *parent) MyClass::MyClass(int *parent)
: m_parent(parent) : m_parent {parent}
{ {
// initialize // initialize
} }
@@ -79,17 +83,21 @@ namespace Name
} }
``` ```
#### b. Other code blocks #### ### b. Other code blocks
```c++ ```c++
if (condition) { if (condition)
{
// code // code
} }
for (int a = 0; a < b; ++b) { for (int a = 0; a < b; ++b)
{
// code // code
} }
switch (a) { switch (a)
{
case 1: case 1:
// blah // blah
case 2: case 2:
@@ -97,17 +105,25 @@ case 2:
default: default:
// blah // blah
} }
{
// code
}
``` ```
#### c. Blocks in switch's case labels #### ### c. Blocks in switch's case labels
```c++ ```c++
switch (var) { switch (var)
case 1: { {
case 1:
{
// declare local variables // declare local variables
// code // code
} }
break; break;
case 2: { case 2:
{
// declare local variables // declare local variables
// code // code
} }
@@ -117,22 +133,29 @@ default:
} }
``` ```
#### d. If-else statements #### ### d. If-else statements
The `else if`/`else` must be on their own lines: The `else if`/`else` must be on their own lines:
```c++ ```c++
if (condition) { if (condition)
{
// code // code
} }
else if (condition) { else if (condition)
{
// code // code
} }
else { else
{
// code // code
} }
``` ```
#### e. Single statement if blocks #### ### e. Single statement if blocks
Most single statement if blocks should look like this: Most single statement if blocks should look like this:
```c++ ```c++
if (condition) if (condition)
a = a + b; a = a + b;
@@ -141,19 +164,23 @@ if (condition)
One acceptable exception to this can be `return`, `break` or `continue` statements, One acceptable exception to this can be `return`, `break` or `continue` statements,
provided that the test condition isn't very long and its body statement occupies only one line. provided that the test condition isn't very long and its body statement occupies only one line.
However you can still choose to use the first rule. However you can still choose to use the first rule.
```c++ ```c++
if (a > 0) return; if (a > 0) return;
while (p) { while (p)
{
// ... // ...
if (!b) continue; if (!b) continue;
} }
``` ```
#### f. Acceptable conditions to omit braces #### ### f. Acceptable conditions to omit braces
When the conditional statement in `if`/`else` has only one line and its body occupy only one line, When the conditional statement in `if`/`else` has only one line and its body occupy only one line,
this also applies to loops statements. this also applies to loops statements. \
Notice that for a series of `if - else` branches, if one branch needs braces then all branches must add braces. Notice that for a series of `if - else` branches, if one branch needs braces then all branches must add braces.
```c++ ```c++
if (a < b) // conditional statement if (a < b) // conditional statement
do(a); // body do(a); // body
@@ -165,21 +192,27 @@ else if (a > b)
else else
do(c); do(c);
if (a < b) { if (a < b)
{
do(a); do(a);
} }
else if (a > b) { // curly braces required here, then all branches should also add them else if (a > b)
{
// curly braces required here, then all branches should also add them
do(b); do(b);
do(d); do(d);
} }
else { else
{
do(c); do(c);
} }
``` ```
#### g. Brace enclosed initializers #### ### g. Brace enclosed initializers
Unlike single-line functions, you must not insert spaces between the brackets and concluded expressions.<br/>
Unlike single-line functions, you must not insert spaces between the brackets and concluded expressions. \
But you must insert a space between the variable name and initializer. But you must insert a space between the variable name and initializer.
```c++ ```c++
Class obj {}; // empty Class obj {}; // empty
Class obj {expr}; Class obj {expr};
@@ -187,28 +220,33 @@ Class obj {expr1, /*...,*/ exprN};
QVariantMap map {{"key1", 5}, {"key2", 10}}; QVariantMap map {{"key1", 5}, {"key2", 10}};
``` ```
### 2. Indentation ### ## 2. Indentation
4 spaces. 4 spaces.
### 3. File encoding and line endings ### ## 3. 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 specific files need other encodings/line endings.
### 4. Initialization lists ### ## 4. 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 initialization colon should be indented and in its own line along with first argument. The rest of the arguments should be indented too and have the comma prepended.
```c++ ```c++
myClass::myClass(int a, int b, int c, int d) myClass::myClass(int a, int b, int c, int d)
: m_a(a) : m_a {a}
, m_b(b) , m_b {b}
, m_c(c) , m_c {c}
, m_d(d) , m_d {d}
{ {
// code // code
} }
``` ```
### 5. Enums ### ## 5. Enums
Enums should be vertical. This will allow for more easily readable diffs. The members should be indented. Enums should be vertical. This will allow for more easily readable diffs. The members should be indented.
```c++ ```c++
enum Days enum Days
{ {
@@ -222,11 +260,14 @@ enum Days
}; };
``` ```
### 6. Names ### ## 6. Names
All names should be camelCased. All names should be camelCased.
#### a. Type names and namespaces #### ### a. Type names and namespaces
Type names and namespaces start with Upper case letter (except POD types). Type names and namespaces start with Upper case letter (except POD types).
```c++ ```c++
class ClassName {}; class ClassName {};
@@ -241,14 +282,18 @@ namespace NamespaceName
} }
``` ```
#### b. Variable names #### ### b. Variable names
Variable names start with lower case letter. Variable names start with lower case letter.
```c++ ```c++
int myVar; int myVar;
``` ```
#### c. Private member variable names #### ### c. Private member variable names
Private member variable names start with lower case letter and should have ```m_``` prefix. Private member variable names start with lower case letter and should have ```m_``` prefix.
```c++ ```c++
class MyClass class MyClass
{ {
@@ -256,23 +301,26 @@ class MyClass
} }
``` ```
### 7. Header inclusion order ### ## 7. Header inclusion order
The headers should be placed in the following group order:
1. Module header (in .cpp)
2. C++ Standard Library headers
3. System headers
4. Boost library headers
5. Libtorrent headers
6. Qt headers
7. qBittorrent's own headers, starting from the *base* headers.
The headers should be ordered alphabetically within each group. The headers should be placed in the following group order:
If there are conditionals for the same header group, then put them at the bottom of the respective group.
1. Module header (in .cpp)
2. C++ Standard Library headers
3. System headers
4. Boost library headers
5. Libtorrent headers
6. Qt headers
7. qBittorrent's own headers, starting from the *base* headers.
The headers should be ordered alphabetically within each group. \
If there are conditionals for the same header group, then put them at the bottom of the respective group. \
If there are conditionals that contain headers from several different header groups, then put them above the "qBittorrent's own headers" group. If there are conditionals that contain headers from several different header groups, then put them above the "qBittorrent's own headers" group.
One exception is the header containing the library version (for example, QtGlobal), this particular header isn't constrained by the aforementioned order. One exception is the header containing the library version (for example, QtGlobal), this particular header isn't constrained by the aforementioned order.
Example: Example:
```c++ ```c++
// file: examplewidget.cpp // file: examplewidget.cpp
@@ -322,8 +370,10 @@ Example:
#include "ui_examplewidget.h" #include "ui_examplewidget.h"
``` ```
### 8. Include guard ### ## 8. Include guard
`#pragma once` should be used instead of "include guard" in new code: `#pragma once` should be used instead of "include guard" in new code:
```c++ ```c++
// examplewidget.h // examplewidget.h
@@ -338,75 +388,77 @@ class ExampleWidget : public QWidget
``` ```
### 9. Misc ### ## 9. Misc
* Line breaks for long lines with operation: * Line breaks for long lines with operation:
```c++ ```c++
a += "b" a += "b"
+ "c" + "c"
+ "d"; + "d";
``` ```
* **auto** keyword * **auto** keyword
We allow the use of the **auto** keyword only where it is strictly necessary We allow the use of the **auto** keyword only where it is strictly necessary (for example, to declare a lambda object, etc.), or where it **enhances** the readability of the code. \
(for example, to declare a lambda object, etc.), or where it **enhances** the readability of the code. Declarations for which one can gather enough information about the object interface (type) from its name or the usage pattern (an iterator or a loop variable are good examples of clear patterns) or the right part of the expression nicely fit here.
Declarations for which one can gather enough information about the object interface (type) from its name
or the usage pattern (an iterator or a loop variable are good examples of clear patterns) When weighing whether to use an auto-typed variable please think about potential reviewers of your code, who will read it as a plain diff (on github.com, for instance). \
or the right part of the expression nicely fit here.<br/> Please make sure that such reviewers can understand the code completely and without excessive effort.
<br/>
When weighing whether to use an auto-typed variable please think about potential reviewers of your code, Some valid use cases:
who will read it as a plain diff (on github.com, for instance). Please make sure that such reviewers can
understand the code completely and without excessive effort.<br/> * Container iteration and casts:
<br/>
Some valid use cases: ```c++
```c++ template <typename List>
template <typename List> void doSomethingWithList(const List &list)
void doSomethingWithList(const List &list) {
{ foreach (const auto &item, list)
foreach (const auto &item, list) { {
// we don't know item type here so we use 'auto' keyword // we don't know item type here so we use 'auto' keyword
// do something with item // do something with item
}
} }
}
for (auto it = container.begin(), end = container.end(); it != end; ++it) { for (auto it = container.begin(), end = container.end(); it != end; ++it)
// we don't need to know the exact iterator type, {
// because all iterators have the same interface // we don't need to know the exact iterator type,
} // because all iterators have the same interface
}
auto spinBox = static_cast<QSpinBox*>(sender()); auto spinBox = static_cast<QSpinBox*>(sender());
// we know the variable type based on the right-hand expression // we know the variable type based on the right-hand expression
``` ```
* Notice the spaces in the following specific situations: * Notice the spaces in the following specific situations:
```c++
// Before and after the assignment and other binary (and ternary) operators there should be a space
// There should not be a space between increment/decrement and its operand
a += 20;
a = (b <= MAX_B ? b : MAX_B);
++a;
--b;
for (int a = 0; a < b; ++b) { ```c++
} // Before and after the assignment and other binary (and ternary) operators there should be a space
// There should not be a space between increment/decrement and its operand
// Range-based for loop, spaces before and after the colon a += 20;
for (auto i : container) { a = (b <= MAX_B ? b : MAX_B);
} ++a;
--b;
// Derived class, spaces before and after the colon for (int a = 0; a < b; ++b)
class Derived : public Base {
{ }
}; // Range-based for loop, spaces before and after the colon
``` for (auto i : container)
{
}
// Derived class, spaces before and after the colon
class Derived : public Base
{
};
```
* Prefer pre-increment, pre-decrement operators * Prefer pre-increment, pre-decrement operators
```c++
++i, --j; // Yes ```c++
i++, j--; // No ++i, --j; // Yes
``` i++, j--; // No
```
* private/public/protected must not be indented * private/public/protected must not be indented
@@ -414,7 +466,8 @@ i++, j--; // No
* Method definitions aren't allowed in header files * Method definitions aren't allowed in header files
### 10. Git commit message ### ## 10. Git commit message
1. Limit the subject line to 50 characters. Subject should contain only the very essence of the changes (you should avoid extra details and internals) 1. Limit the subject line to 50 characters. Subject should contain only the very essence of the changes (you should avoid extra details and internals)
2. Separate subject from body with a blank line 2. Separate subject from body with a blank line
3. Capitalize the subject line 3. Capitalize the subject line
@@ -424,6 +477,7 @@ i++, j--; // No
7. Use the body to explain what and why vs. how 7. Use the body to explain what and why vs. how
8. If commit fixes a reported issue, mention it in the message body (e.g. `Closes #4134.`) 8. If commit fixes a reported issue, mention it in the message body (e.g. `Closes #4134.`)
### 11. Not covered above ### ## 11. Not covered above
If something isn't covered above, just follow the same style the file you are editing has.
If something isn't covered above, just follow the same style the file you are editing has. \
*This guide is not exhaustive and the style for a particular piece of code not specified here will be determined by project members on code review.* *This guide is not exhaustive and the style for a particular piece of code not specified here will be determined by project members on code review.*

View File

@@ -1,4 +1,77 @@
Unreleased - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.0 Wed Nov 25 2020 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.1
- FEATURE: Allow progress bar styling from custom themes (jagannatharjun)
- FEATURE: Allow adding torrents using "Paste" key sequence (Chocobo1)
- FEATURE: Add Latgalian translation (sledgehammer999)
- BUGFIX: Prevent resume data to be saved for removed torrent (glassez)
- BUGFIX: Clarify connection protocol choice label (FranciscoPombal)
- BUGFIX: Fix crash when clicked outside the table of torrent content view (jagannatharjun)
- BUGFIX: Don't resume "paused" torrents when put into "checking" state by libtorrent (glassez)
- BUGFIX: Fix torrent state calculation (glassez)
- BUGFIX: Align integer data to right in torrent content view (jagannatharjun)
- WEBUI: Place WebUI RSS description in sandboxed iframe (Sepro)
- WEBUI: Avoid settings being reset via WebAPI (Chocobo1)
- WEBUI: Fix toggling advanced option in WebUI (thalieht)
- WEBUI: Expose contentPath in WebAPI torrents/info (FranciscoPombal)
- WEBUI: Fix the issue that IPv6 address can't be banned (brvphoenix)
- RSS: Fix confusion in date format description (Thomas De Rocker)
- WINDOWS: Update dutch.nsi (Thomas De Rocker)
- LINUX: Update .desktop file translations (sledgehammer999)
Thu Oct 22 2020 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.0.1
- WINDOWS: NSIS: Update Italian translation (bovirus)
Sun Oct 18 2020 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.0
- FEATURE: Many UI elements colors are themeable now (jagannatharjun)
- FEATURE: Allow changing GUI icons from theme bundles (jagannatharjun)
- FEATURE: Notify user when torrent moving finished (glassez)
- FEATURE: Shortcut CTRL + I opens Statistics window (LoopsGod)
- FEATURE: Add RSS functionality in Web UI (Sepro)
- FEATURE: Drop ".unwanted folder" feature (glassez)
- FEATURE: Expose libtorrent peer_turnover, max_concurrent_http_announces, no_connect_privileged_ports settings (Sophist, an0n666, NotTsunami)
- BUGFIX: Fix typo in Options dialog (Andrei Stepanov)
- BUGFIX: Remove "requires restart" from network interface settings (an0n666)
- BUGFIX: Rename "Create subfolder" to "Keep top-level folder" (thalieht)
- BUGFIX: Show tooltip for some properties in transfer list (Nick Korotysh)
- BUGFIX: Fix calculation of torrent current state (glassez)
- BUGFIX: Improve detecting completed files when adding, rechecking or moving a torrent (glassez)
- BUGFIX: Fixed broken announce logic in embedded tracker causing failures in some cases (FranciscoPombal)
- BUGFIX: Disable checkbox if torrent doesn't have root folder (thalieht)
- BUGFIX: Update country flag icons with upstream (Chocobo1)
- BUGFIX: Private torrent: If tracker entry is edited clear old peer list. Also don't allow user to manually add peers. (an0n666)
- BUGFIX: Fix large strings not visible in log widget (jagannatharjun)
- BUGFIX: Disable edit action in Peer list widget (Chocobo1)
- BUGFIX: Add a scroll area to torrent creator dialog (Ernesto Castellotti)
- BUGFIX: Content tab: Open double-clicked folder regardless on which column the click happens (Chocobo1)
- BUGFIX: "Open containing folder" on a folder now opens it in its parent folder (Chocobo1)
- BUGFIX: Fix GeoDB download in systems with non-C locales (FranciscoPombal)
- BUGFIX: Fix peer blocked message (FranciscoPombal)
- BUGFIX: Make more robust the banning of selected peers from the list (NotTsunami)
- BUGFIX: Use toned green color for downloading pieces in Pieces bar (jagannatharjun)
- BUGFIX: Correctly fill whole width of speed graph (jagannatharjun)
- BUGFIX: Fix impossible speed in speed graph (jagannatharjun)
- WEBUI: Hide additional search filters on small screens (Thomas Piccirello)
- WEBUI: Shrink search bar on small screens (Thomas Piccirello)
- WEBUI: Fix search categories only working in English (Thomas Piccirello)
- WEBUI: Add Trackers section to sidebar (Thomas Piccirello)
- WEBUI: Fix Enter button behavior in textarea (Tom Piccirello)
- WEBUI: Fix wrong file renaming selection range (MR)
- WEBUI: Preselect "Default save path" in watched folders (thalieht)
- WEBUI: Fix banning peers (brvphoenix)
- WEBUI: Fix seeding time checkbox placement (Chocobo1)
- WEBUI: Bump Web API version (Thomas Piccirello)
- RSS: Fix renaming RSS autodownload rule (glassez)
- RSS: Fix RSS article is not marked as "read" when torrent is downloaded (glassez)
- SEARCH: Update minimum Python version to 3.5.0 (ngosang)
- SEARCH: Make middle-click close search tabs (Will Da Silva)
- WINDOWS: NSIS: Update Dutch translation (Thomas De Rocker)
- WINDOWS: NSIS: Change the installers uninstallation question to clear confusion (an0n666)
- LINUX: Fix typo in systemd service file (Shane Allgeier)
- LINUX: Don't use HTML in tray tooltip (thalieht)
- LINUX: Don't create 'data' subdirectory in XDG_DATA_HOME (lbilli)
- LINUX/MACOS: Add HTTPS tracker certificate validation option (NotTsunami)
- OTHER: Many CMake improvements (FranciscoPombal)
- OTHER: Support for libtorrent 1.1.x is dropped (Chocobo1)
- OTHER: Many code cleanups and improvements (FranciscoPombal, Chocobo1, glassez)
Tue Dec 03 2019 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.2.0 Tue Dec 03 2019 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.2.0
- FEATURE: Libtorrent 1.2.x series are supported now (glassez) - FEATURE: Libtorrent 1.2.x series are supported now (glassez)
@@ -31,7 +104,7 @@ Tue Dec 03 2019 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.2.0
- BUGFIX: Remove the max half-open connections option (thalieht) - BUGFIX: Remove the max half-open connections option (thalieht)
- BUGFIX: Center align the section labels in advanced settings (thalieht) - BUGFIX: Center align the section labels in advanced settings (thalieht)
- BUGFIX: Add documentation links to some advanced settings (thalieht) - BUGFIX: Add documentation links to some advanced settings (thalieht)
- BUGFIX: Impove DownloadManager code (glassez) - BUGFIX: Improve DownloadManager code (glassez)
- BUGFIX: Limit DownloadHandler max redirection to 20 (Chocobo1) - BUGFIX: Limit DownloadHandler max redirection to 20 (Chocobo1)
- BUGFIX: Log DownloadManager SSL errors (Chocobo1) - BUGFIX: Log DownloadManager SSL errors (Chocobo1)
- BUGFIX: Force recheck multiple torrents one by one (glassez) - BUGFIX: Force recheck multiple torrents one by one (glassez)
@@ -262,10 +335,10 @@ Tue Dec 03 2019 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.2.0
- BUGFIX: Restore torrent in two steps (glassez) - BUGFIX: Restore torrent in two steps (glassez)
- BUGFIX: Improve scaling of speed graphs (dzmat) - BUGFIX: Improve scaling of speed graphs (dzmat)
- BUGFIX: Add isNetworkFileSystem() detection on Windows. This allows network mounts to be monitored correctly by polling timer. (Chocobo1) - BUGFIX: Add isNetworkFileSystem() detection on Windows. This allows network mounts to be monitored correctly by polling timer. (Chocobo1)
- BUGFIX: Reduce horizontal graphs resolution. Improves perfomance. (dzmat) - BUGFIX: Reduce horizontal graphs resolution. Improves performance. (dzmat)
- BUGFIX: Don't recheck just checked torrent (mj-p, glassez) - BUGFIX: Don't recheck just checked torrent (mj-p, glassez)
- BUGFIX: Add SMB2 magic number (Chocobo1) - BUGFIX: Add SMB2 magic number (Chocobo1)
- BUGFIX: Restore startup perfomance to v4.1.2 times. Needs at least libtorrent 1.1.10 (sledgehammer999) - BUGFIX: Restore startup performance to v4.1.2 times. Needs at least libtorrent 1.1.10 (sledgehammer999)
- BUGFIX: Make strings actually translatable (sledgehammer999) - BUGFIX: Make strings actually translatable (sledgehammer999)
- WEBUI: Handle downloading .torrent file as success (Tom Piccirello) - WEBUI: Handle downloading .torrent file as success (Tom Piccirello)
- WEBUI: Fix Alternative Web UI to be available (glassez) - WEBUI: Fix Alternative Web UI to be available (glassez)
@@ -336,7 +409,7 @@ Tue Dec 03 2019 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.2.0
- BUGFIX: Improve torrent initialization (glassez) - BUGFIX: Improve torrent initialization (glassez)
- BUGFIX: Save resume data on torrent change events (glassez) - BUGFIX: Save resume data on torrent change events (glassez)
- BUGFIX: Increase default resume data save interval (Chocobo1) - BUGFIX: Increase default resume data save interval (Chocobo1)
- BUGFIX: Work around crash when procesing recursive download. Closes #9086 (Chocobo1) - BUGFIX: Work around crash when processing recursive download. Closes #9086 (Chocobo1)
- BUGFIX: Reduce queries to python version (Chocobo1) - BUGFIX: Reduce queries to python version (Chocobo1)
- BUGFIX: Disable certain mouse wheel events in Options dialog (Chocobo1) - BUGFIX: Disable certain mouse wheel events in Options dialog (Chocobo1)
- WEBUI: Send all rechecks in one request (Thomas Piccirello) - WEBUI: Send all rechecks in one request (Thomas Piccirello)
@@ -823,7 +896,7 @@ Tue Dec 03 2019 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.2.0
- COSMETIC: Change RSS view layout to horizontal. Closes #5920. (Chocobo1) - COSMETIC: Change RSS view layout to horizontal. Closes #5920. (Chocobo1)
- OSX: Fix crash on exit using Qt4. (Yez Ezey) - OSX: Fix crash on exit using Qt4. (Yez Ezey)
- OSX: Change QSettings to IniFormat on macOS. Closes #5770 #5808. (Yez Ezey) - OSX: Change QSettings to IniFormat on macOS. Closes #5770 #5808. (Yez Ezey)
- LINUX: Workaround a Qt5 bug which results in a flood of network interface change singals. (Eugene Shalygin) - LINUX: Workaround a Qt5 bug which results in a flood of network interface change signals. (Eugene Shalygin)
- OTHER: Turkish translation for installer. (Burak Yavuz) - OTHER: Turkish translation for installer. (Burak Yavuz)
- OTHER: Update portugueseBR for installer. (DaRKSoM) - OTHER: Update portugueseBR for installer. (DaRKSoM)
- OTHER: Update portuguese for installer. (EdwardLinux) - OTHER: Update portuguese for installer. (EdwardLinux)
@@ -2170,7 +2243,7 @@ Tue Dec 03 2019 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.2.0
- FEATURE: Added "Unread" item to RSS feed list to display all unread news - FEATURE: Added "Unread" item to RSS feed list to display all unread news
- FEATURE: If a torrent contains a torrent file, process downloaded torrent file too - FEATURE: If a torrent contains a torrent file, process downloaded torrent file too
- FEATURE: A random listening port can be chosen automatically - FEATURE: A random listening port can be chosen automatically
- BUGFIX: torrent resume code rewrited - BUGFIX: torrent resume code rewritten
- BUGFIX: Fixed uTorrent spoofing code - BUGFIX: Fixed uTorrent spoofing code
- BUGFIX: Greatly improved column sorting code - BUGFIX: Greatly improved column sorting code
- BUGFIX: Possibility to create trackerless torrents - BUGFIX: Possibility to create trackerless torrents

1
TODO
View File

@@ -1,2 +1 @@
See https://blueprints.launchpad.net/qbittorrent/ See https://blueprints.launchpad.net/qbittorrent/

24
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for qbittorrent v4.3.0alpha. # Generated by GNU Autoconf 2.69 for qbittorrent v4.3.1.
# #
# Report bugs to <bugs.qbittorrent.org>. # Report bugs to <bugs.qbittorrent.org>.
# #
@@ -580,8 +580,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='qbittorrent' PACKAGE_NAME='qbittorrent'
PACKAGE_TARNAME='qbittorrent' PACKAGE_TARNAME='qbittorrent'
PACKAGE_VERSION='v4.3.0alpha' PACKAGE_VERSION='v4.3.1'
PACKAGE_STRING='qbittorrent v4.3.0alpha' PACKAGE_STRING='qbittorrent v4.3.1'
PACKAGE_BUGREPORT='bugs.qbittorrent.org' PACKAGE_BUGREPORT='bugs.qbittorrent.org'
PACKAGE_URL='https://www.qbittorrent.org/' PACKAGE_URL='https://www.qbittorrent.org/'
@@ -1302,7 +1302,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures qbittorrent v4.3.0alpha to adapt to many kinds of systems. \`configure' configures qbittorrent v4.3.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1373,7 +1373,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of qbittorrent v4.3.0alpha:";; short | recursive ) echo "Configuration of qbittorrent v4.3.1:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@@ -1509,7 +1509,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
qbittorrent configure v4.3.0alpha qbittorrent configure v4.3.1
generated by GNU Autoconf 2.69 generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc. Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1648,7 +1648,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by qbittorrent $as_me v4.3.0alpha, which was It was created by qbittorrent $as_me v4.3.1, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@ $ $0 $@
@@ -3826,7 +3826,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE='qbittorrent' PACKAGE='qbittorrent'
VERSION='v4.3.0alpha' VERSION='v4.3.1'
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
@@ -6343,7 +6343,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by qbittorrent $as_me v4.3.0alpha, which was This file was extended by qbittorrent $as_me v4.3.1, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@@ -6401,7 +6401,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
qbittorrent config.status v4.3.0alpha qbittorrent config.status v4.3.1
configured by $0, generated by GNU Autoconf 2.69, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"
@@ -7659,7 +7659,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by qbittorrent $as_me v4.3.0alpha, which was This file was extended by qbittorrent $as_me v4.3.1, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@@ -7717,7 +7717,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
qbittorrent config.status v4.3.0alpha qbittorrent config.status v4.3.1
configured by $0, generated by GNU Autoconf 2.69, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"

View File

@@ -1,4 +1,4 @@
AC_INIT([qbittorrent], [v4.3.0alpha], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/]) AC_INIT([qbittorrent], [v4.3.1], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/])
AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AC_PROG_CC AC_PROG_CC

View File

@@ -0,0 +1 @@
# empty

View File

@@ -74,6 +74,6 @@
<url type="translate">https://github.com/qbittorrent/qBittorrent/wiki/How-to-translate-qBittorrent</url> <url type="translate">https://github.com/qbittorrent/qBittorrent/wiki/How-to-translate-qBittorrent</url>
<content_rating type="oars-1.1"/> <content_rating type="oars-1.1"/>
<releases> <releases>
<release version="4.1.5" date="2018-12-24"/> <release version="4.3.1" date="2020-11-25"/>
</releases> </releases>
</component> </component>

View File

@@ -11,8 +11,6 @@ Type=Application
StartupNotify=false StartupNotify=false
StartupWMClass=qbittorrent StartupWMClass=qbittorrent
Keywords=bittorrent;torrent;magnet;download;p2p; Keywords=bittorrent;torrent;magnet;download;p2p;
# Translations
Comment[oc]=Telecargar e partejar de fichièrs amb BitTorrent Comment[oc]=Telecargar e partejar de fichièrs amb BitTorrent
GenericName[oc]=Client BitTorrent GenericName[oc]=Client BitTorrent
Name[oc]=qBittorrent Name[oc]=qBittorrent
@@ -22,8 +20,8 @@ Name[af]=qBittorrent
Comment[ar]=نزّل وشارك الملفات عبر كيوبت‎تورنت Comment[ar]=نزّل وشارك الملفات عبر كيوبت‎تورنت
GenericName[ar]=عميل بت‎تورنت GenericName[ar]=عميل بت‎تورنت
Name[ar]=كيوبت‎تورنت Name[ar]=كيوبت‎تورنت
Comment[be]=Сцягванне і раздача файлаў праз пратакол BitTorrent Comment[be]=Спампоўванне і раздача файлаў праз пратакол BitTorrent
GenericName[be]=BitTorrent-кліент GenericName[be]=Кліент BitTorrent
Name[be]=qBittorrent Name[be]=qBittorrent
Comment[bg]=Сваляне и споделяне на файлове чрез BitTorrent Comment[bg]=Сваляне и споделяне на файлове чрез BitTorrent
GenericName[bg]=BitTorrent клиент GenericName[bg]=BitTorrent клиент
@@ -34,19 +32,19 @@ Name[bn]=কিউবি্টটরেন্ট
Comment[bs]=Preuzmi i dijeli datoteke preko BitTorrent-a Comment[bs]=Preuzmi i dijeli datoteke preko BitTorrent-a
GenericName[bs]=BitTorrent klijent GenericName[bs]=BitTorrent klijent
Name[bs]=qBittorrent Name[bs]=qBittorrent
Comment[ca]=Baixeu i compartiu fitxers mitjançant BitTorrent Comment[ca]=Baixeu i compartiu fitxers amb el BitTorrent
GenericName[ca]=Client de BitTorrent GenericName[ca]=Client de BitTorrent
Name[ca]=qBittorrent Name[ca]=qBittorrent
Comment[cs]=Stahování a sdílení souborů přes síť BitTorrent Comment[cs]=Stahování a sdílení souborů přes síť BitTorrent
GenericName[cs]=BitTorrent klient GenericName[cs]=BitTorrent klient
Name[cs]=qBittorrent Name[cs]=qBittorrent
Comment[da]=Download og del filer over BitTorrent Comment[da]=Download og del filer over BitTorrent
GenericName[da]=BitTorrent klient GenericName[da]=BitTorrent-klient
Name[da]=qBittorrent Name[da]=qBittorrent
Comment[de]=Über BitTorrent Dateien herunterladen und teilen Comment[de]=Über BitTorrent Dateien herunterladen und teilen
GenericName[de]=BitTorrent Client GenericName[de]=BitTorrent Client
Name[de]=qBittorrent Name[de]=qBittorrent
Comment[el]=Κάντε λήψη και ανταλάξτε αρχεία μέσω BitTorrent Comment[el]=Κάντε λήψη και ανταλλάξτε αρχεία μέσω BitTorrent
GenericName[el]=Πελάτης BitTorrent GenericName[el]=Πελάτης BitTorrent
Name[el]=qBittorrent Name[el]=qBittorrent
Comment[en_GB]=Download and share files over BitTorrent Comment[en_GB]=Download and share files over BitTorrent
@@ -55,7 +53,7 @@ Name[en_GB]=qBittorrent
Comment[es]=Descargue y comparta archivos por BitTorrent Comment[es]=Descargue y comparta archivos por BitTorrent
GenericName[es]=Cliente BitTorrent GenericName[es]=Cliente BitTorrent
Name[es]=qBittorrent Name[es]=qBittorrent
Comment[eu]=Jeitsi eta elkarbanatu agiriak BitTorrent-en Comment[eu]=Jeitsi eta elkarbanatu agiriak BitTorrent bidez
GenericName[eu]=BitTorrent bezeroa GenericName[eu]=BitTorrent bezeroa
Name[eu]=qBittorrent Name[eu]=qBittorrent
Comment[fa]=دانلود و به اشتراک گذاری فایل های بوسیله بیت تورنت Comment[fa]=دانلود و به اشتراک گذاری فایل های بوسیله بیت تورنت
@@ -97,15 +95,18 @@ Name[ja]=qBittorrent
Comment[ka]=ჩამოტვირთე და გააზიარე ფაილები Bittorrent-ის საშუალებით Comment[ka]=ჩამოტვირთე და გააზიარე ფაილები Bittorrent-ის საშუალებით
GenericName[ka]=BitTorrent კლიენტი GenericName[ka]=BitTorrent კლიენტი
Name[ka]=qBittorrent Name[ka]=qBittorrent
Comment[ko]=비트토런트를 통해 파일을 다운로드하고 공유합니다 Comment[ko]=비트토런트를 통해 파일을 고 공유합니다
GenericName[ko]=비트토런트 클라이언트 GenericName[ko]=비트토런트 클라이언트
Name[ko]=큐빗토런트 Name[ko]=qBittorrent
Comment[zh]=通过 BitTorrent 下载和分享文件 Comment[zh]=通过 BitTorrent 下载和分享文件
GenericName[zh]=BitTorrent 客户端 GenericName[zh]=BitTorrent 客户端
Name[zh]=qBittorrent Name[zh]=qBittorrent
Comment[lt]=Atsisiųskite bei dalinkitės failais BitTorrent tinkle Comment[lt]=Atsisiųskite bei dalinkitės failais BitTorrent tinkle
GenericName[lt]=BitTorrent klientas GenericName[lt]=BitTorrent klientas
Name[lt]=qBittorrent Name[lt]=qBittorrent
Comment[mk]=Превземајте и споделувајте фајлови преку BitTorrent
GenericName[mk]=BitTorrent клиент
Name[mk]=qBittorrent
Comment[nb]=Last ned og del filer over BitTorrent Comment[nb]=Last ned og del filer over BitTorrent
GenericName[nb]=BitTorrent-klient GenericName[nb]=BitTorrent-klient
Name[nb]=qBittorrent Name[nb]=qBittorrent
@@ -113,7 +114,7 @@ Comment[nqo]=ߞߐߕߐ߯ߘߐ ߟߎ߬ ߟߊߖߌ߰ ߞߊ߬ ߓߊ߲߫ ߞߵߊ߬ߟߎ߬ ߘ
GenericName[nqo]=ߓߌߙߏߙߍ߲ߕ ߕߣߐ߬ߓߐ߬ߟߊ GenericName[nqo]=ߓߌߙߏߙߍ߲ߕ ߕߣߐ߬ߓߐ߬ߟߊ
Name[nqo]=ߞߎ߳ߓߌߕߏߙߍ߲ߕ Name[nqo]=ߞߎ߳ߓߌߕߏߙߍ߲ߕ
Comment[nl]=Bestanden downloaden en delen via BitTorrent Comment[nl]=Bestanden downloaden en delen via BitTorrent
GenericName[nl]=BitTorrent-cliënt GenericName[nl]=BitTorrent-client
Name[nl]=qBittorrent Name[nl]=qBittorrent
Comment[pl]=Pobieraj i dziel się plikami przez BitTorrent Comment[pl]=Pobieraj i dziel się plikami przez BitTorrent
GenericName[pl]=Klient BitTorrent GenericName[pl]=Klient BitTorrent
@@ -127,8 +128,8 @@ Name[pt_BR]=qBittorrent
Comment[ro]=Descărcați și partajați fișiere prin BitTorrent Comment[ro]=Descărcați și partajați fișiere prin BitTorrent
GenericName[ro]=Client BitTorrent GenericName[ro]=Client BitTorrent
Name[ro]=qBittorrent Name[ro]=qBittorrent
Comment[ru]=Скачивайте и делитесь файлами с помощью BitTorrent Comment[ru]=Обмен файлами по сети BitTorrent
GenericName[ru]=BitTorrent-клиент GenericName[ru]=Клиент сети BitTorrent
Name[ru]=qBittorrent Name[ru]=qBittorrent
Comment[sk]=Sťahovanie a zdieľanie súborov prostredníctvom siete BitTorrent Comment[sk]=Sťahovanie a zdieľanie súborov prostredníctvom siete BitTorrent
GenericName[sk]=Klient siete BitTorrent GenericName[sk]=Klient siete BitTorrent
@@ -146,16 +147,19 @@ Name[sv]=qBittorrent
Comment[uz@Latn]=BitTorrent orqali fayllarni yuklab olish va baham korish Comment[uz@Latn]=BitTorrent orqali fayllarni yuklab olish va baham korish
GenericName[uz@Latn]=BitTorrent mijozi GenericName[uz@Latn]=BitTorrent mijozi
Name[uz@Latn]=qBittorrent Name[uz@Latn]=qBittorrent
Comment[te]=క్యు బిట్ టొరెంట్ తో ఫైల్స్ దిగుమతి చేసుకోండి , పంచుకోండి Comment[ltg]=Atsasyuteit i daleit failus ar BitTorrent
GenericName[te]=క్యు బిట్ టొరెంట్ క్లయింట్ GenericName[ltg]=BitTorrent klients
Name[te]=క్యు బిట్ టొరెంట్ Name[ltg]=qBittorrent
Comment[hi_IN]= अपनी फाइलें BitTorrent के माध्यम से डाउनलोड आैर साॅझा करें Comment[hi_IN]= अपनी फाइलें BitTorrent के माध्यम से डाउनलोड आैर साॅझा करें
GenericName[hi_IN]=BitTorrent उपभोक्ता GenericName[hi_IN]=BitTorrent उपभोक्ता
Name[hi_IN]=qBittorrent Name[hi_IN]=qBittorrent
Comment[tr]=Dosyaları BitTorrent üzerinden indirin ve paylaşın Comment[tr]=Dosyaları BitTorrent üzerinden indirin ve paylaşın
GenericName[tr]=BitTorrent istemcisi GenericName[tr]=BitTorrent istemcisi
Name[tr]=qBittorrent Name[tr]=qBittorrent
Comment[uk]=Завантажувати і обмінюватися файлами через BitTorrent Comment[ur]=BitTorrent پر فائلوں کو ڈاؤن لوڈ کریں اور اشتراک کریں
GenericName[ur]=قیو بٹ ٹورنٹ کلائنٹ
Name[ur]=قیو بٹ ٹورنٹ
Comment[uk]=Завантажуйте та поширюйте файли через BitTorrent
GenericName[uk]=BitTorrent-клієнт GenericName[uk]=BitTorrent-клієнт
Name[uk]=qBittorrent Name[uk]=qBittorrent
Comment[vi]=Tải về và chia sẻ các tập tin thông qua BitTorrent Comment[vi]=Tải về và chia sẻ các tập tin thông qua BitTorrent
@@ -179,9 +183,15 @@ Name[eo]=qBittorrent
Comment[mn_MN]=BitTorrent ашиглан файлуудыг татаж түгээх Comment[mn_MN]=BitTorrent ашиглан файлуудыг татаж түгээх
GenericName[mn_MN]=BitTorrent үйлчлүүлэгч GenericName[mn_MN]=BitTorrent үйлчлүүлэгч
Name[mn_MN]=qBittorrent Name[mn_MN]=qBittorrent
Comment[ta]=BitTorrent வழியாக கோப்புகளை பதிவிறக்க மற்றும் பகிர
GenericName[ta]=BitTorrent வாடிக்கையாளர்
Name[ta]=qBittorrent
Comment[ne_NP]=फाइलहरू डाउनलोड गर्नुहोस् र BitTorrent मा साझा गर्नुहोस् Comment[ne_NP]=फाइलहरू डाउनलोड गर्नुहोस् र BitTorrent मा साझा गर्नुहोस्
GenericName[ne_NP]=BitTorrent क्लाइन्ट GenericName[ne_NP]=BitTorrent क्लाइन्ट
Name[ne_NP]=qBittorrent Name[ne_NP]=qBittorrent
Comment[te]=క్యు బిట్ టొరెంట్ తో ఫైల్స్ దిగుమతి చేసుకోండి , పంచుకోండి
GenericName[te]=క్యు బిట్ టొరెంట్ క్లయింట్
Name[te]=క్యు బిట్ టొరెంట్
Comment[en_AU]=Download and share files over BitTorrent Comment[en_AU]=Download and share files over BitTorrent
GenericName[en_AU]=BitTorrent client GenericName[en_AU]=BitTorrent client
Name[en_AU]=qBittorrent Name[en_AU]=qBittorrent

View File

@@ -8,7 +8,8 @@ TRANSLATORS:
english message to help you with the translation. english message to help you with the translation.
4. Edit only the part inside the quotation marks(""). Unless you know 4. Edit only the part inside the quotation marks(""). Unless you know
what you are doing. what you are doing.
5. Save the files with utf8 encoding and BOM. 5. Save the files with UTF-8 encoding, without BOM
(this should be the default in any modern text editor).
6. Submit your changes: 1) as a pull request to the official git repo or 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 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 translations for qbt itself

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_AFRIKAANS} "qBittorrent (required)" LangString inst_qbt_req ${LANG_AFRIKAANS} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_ALBANIAN} "qBittorrent (required)" LangString inst_qbt_req ${LANG_ALBANIAN} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_ARABIC} "qBittorrent (مطلوب)" LangString inst_qbt_req ${LANG_ARABIC} "qBittorrent (مطلوب)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_BASQUE} "qBittorrent (beharrezkoa)" LangString inst_qbt_req ${LANG_BASQUE} "qBittorrent (beharrezkoa)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_BELARUSIAN} "qBittorrent (required)" LangString inst_qbt_req ${LANG_BELARUSIAN} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_BOSNIAN} "qBittorrent (required)" LangString inst_qbt_req ${LANG_BOSNIAN} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_BRETON} "qBittorrent (required)" LangString inst_qbt_req ${LANG_BRETON} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_BULGARIAN} "qBittorrent (required)" LangString inst_qbt_req ${LANG_BULGARIAN} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_CATALAN} "qBittorrent (required)" LangString inst_qbt_req ${LANG_CATALAN} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_CROATIAN} "qBittorrent (neophodno)" LangString inst_qbt_req ${LANG_CROATIAN} "qBittorrent (neophodno)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_CZECH} "qBittorrent (vyžadováno)" LangString inst_qbt_req ${LANG_CZECH} "qBittorrent (vyžadováno)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_DANISH} "qBittorrent (påkrævet)" LangString inst_qbt_req ${LANG_DANISH} "qBittorrent (påkrævet)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_DUTCH} "qBittorrent (vereist)" LangString inst_qbt_req ${LANG_DUTCH} "qBittorrent (vereist)"
@@ -19,9 +19,9 @@ LangString inst_pathlimit ${LANG_DUTCH} "De Windows-begrenzing voor padlengte ui
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule" ;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
LangString inst_firewallinfo ${LANG_DUTCH} "Uitzondering aan Windows Firewall toevoegen" LangString inst_firewallinfo ${LANG_DUTCH} "Uitzondering aan Windows Firewall toevoegen"
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing." ;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
LangString inst_warning ${LANG_DUTCH} "qBittorrent is actief. Sluit de toepassing voordat u deze update installeert." LangString inst_warning ${LANG_DUTCH} "qBittorrent is actief. Sluit het af voordat u deze update installeert."
;LangString inst_uninstall_question ${LANG_ENGLISH} "Current version will be uninstalled. User settings and torrents will remain intact." ;LangString inst_uninstall_question ${LANG_ENGLISH} "Current version will be uninstalled. User settings and torrents will remain intact."
LangString inst_uninstall_question ${LANG_DUTCH} "Er werd een eerdere installatie gedetecteerd. Deze wordt verwijderd zonder de gebruikersinstellingen te verwijderen." LangString inst_uninstall_question ${LANG_DUTCH} "De huidige versie zal verwijderd worden. Gebruikersinstellingen en torrents blijven intact."
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version." ;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
LangString inst_unist ${LANG_DUTCH} "Vorige versie verwijderen." LangString inst_unist ${LANG_DUTCH} "Vorige versie verwijderen."
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent." ;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
@@ -52,7 +52,7 @@ LangString remove_firewallinfo ${LANG_DUTCH} "Uitzondering uit Windows Firewall
;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data" ;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data"
LangString remove_cache ${LANG_DUTCH} "Torrents en cachegegevens verwijderen" LangString remove_cache ${LANG_DUTCH} "Torrents en cachegegevens verwijderen"
;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling." ;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling."
LangString uninst_warning ${LANG_DUTCH} "qBittorrent is actief. Sluit de toepassing voordat u ze verwijdert." LangString uninst_warning ${LANG_DUTCH} "qBittorrent is actief. Sluit het af voordat u het verwijdert."
;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:" ;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:"
LangString uninst_tor_warn ${LANG_DUTCH} ".torrent-associatie wordt niet verwijderd. Ze is gekoppeld met:" LangString uninst_tor_warn ${LANG_DUTCH} ".torrent-associatie wordt niet verwijderd. Ze is gekoppeld met:"
;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:" ;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_ESPERANTO} "qBittorrent (required)" LangString inst_qbt_req ${LANG_ESPERANTO} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_ESTONIAN} "qBittorrent (required)" LangString inst_qbt_req ${LANG_ESTONIAN} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_FARSI} "qBittorrent (required)" LangString inst_qbt_req ${LANG_FARSI} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_FINNISH} "qBittorrent (pakollinen)" LangString inst_qbt_req ${LANG_FINNISH} "qBittorrent (pakollinen)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_FRENCH} "qBittorrent (requis)" LangString inst_qbt_req ${LANG_FRENCH} "qBittorrent (requis)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_GALICIAN} "qBittorrent (necesario)" LangString inst_qbt_req ${LANG_GALICIAN} "qBittorrent (necesario)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_GERMAN} "qBittorrent (erforderlich)" LangString inst_qbt_req ${LANG_GERMAN} "qBittorrent (erforderlich)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_GREEK} "qBittorrent (απαιτείται)" LangString inst_qbt_req ${LANG_GREEK} "qBittorrent (απαιτείται)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_HEBREW} "qBittorrent (required)" LangString inst_qbt_req ${LANG_HEBREW} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_HUNGARIAN} "qBittorrent (required)" LangString inst_qbt_req ${LANG_HUNGARIAN} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_ICELANDIC} "qBittorrent (required)" LangString inst_qbt_req ${LANG_ICELANDIC} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_INDONESIAN} "qBittorrent (required)" LangString inst_qbt_req ${LANG_INDONESIAN} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_IRISH} "qBittorrent (required)" LangString inst_qbt_req ${LANG_IRISH} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_ITALIAN} "qBittorrent (necessario)" LangString inst_qbt_req ${LANG_ITALIAN} "qBittorrent (necessario)"
@@ -7,7 +7,7 @@ LangString inst_dekstop ${LANG_ITALIAN} "Crea icone sul desktop"
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut" ;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
LangString inst_startmenu ${LANG_ITALIAN} "Crea gruppo programmi" LangString inst_startmenu ${LANG_ITALIAN} "Crea gruppo programmi"
;LangString inst_startup ${LANG_ENGLISH} "Start qBittorrent on Windows start up" ;LangString inst_startup ${LANG_ENGLISH} "Start qBittorrent on Windows start up"
LangString inst_startup ${LANG_ITALIAN} "Avvia qBittorrent all'avvio di Windows" LangString inst_startup ${LANG_ITALIAN} "Esegui qBittorrent all'avvio di Windows"
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent" ;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
LangString inst_torrent ${LANG_ITALIAN} "Apri file .torrent con qBittorrent" LangString inst_torrent ${LANG_ITALIAN} "Apri file .torrent con qBittorrent"
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent" ;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
@@ -15,21 +15,21 @@ LangString inst_magnet ${LANG_ITALIAN} "Apri collegamenti magnet con qBittorrent
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule" ;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
LangString inst_firewall ${LANG_ITALIAN} "Aggiungi regola al firewall di Windows" LangString inst_firewall ${LANG_ITALIAN} "Aggiungi regola al firewall di Windows"
;LangString inst_pathlimit ${LANG_ENGLISH} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)" ;LangString inst_pathlimit ${LANG_ENGLISH} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)"
LangString inst_pathlimit ${LANG_ITALIAN} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)" LangString inst_pathlimit ${LANG_ITALIAN} "Disabilita limite percorso Windows (limite MAX_PATH max 260 caratterin, richiede Windows 10 versione 1607 o successive)"
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule" ;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
LangString inst_firewallinfo ${LANG_ITALIAN} "Aggiunta regola al firewall di Windows" LangString inst_firewallinfo ${LANG_ITALIAN} "Aggiunta regola al firewall di Windows"
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing." ;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
LangString inst_warning ${LANG_ITALIAN} "qBittorrent è in esecuzione. Chiudi l'applicazione prima dell'installazione." LangString inst_warning ${LANG_ITALIAN} "qBittorrent è in esecuzione.%n%nChiudi l'applicazione qBittorrent prima della nuova installazione."
;LangString inst_uninstall_question ${LANG_ENGLISH} "Current version will be uninstalled. User settings and torrents will remain intact." ;LangString inst_uninstall_question ${LANG_ENGLISH} "Current version will be uninstalled. User settings and torrents will remain intact."
LangString inst_uninstall_question ${LANG_ITALIAN} "Current version will be uninstalled. User settings and torrents will remain intact." LangString inst_uninstall_question ${LANG_ITALIAN} "L'attuale versione di qBittorrent verrà disinstallata.%n%nLe impostazioni utente e i torrent rimanno invariati."
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version." ;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
LangString inst_unist ${LANG_ITALIAN} "Disinstallazione versione precedente." LangString inst_unist ${LANG_ITALIAN} "Disinstallazione versione precedente di qBittorrent."
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent." ;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
LangString launch_qbt ${LANG_ITALIAN} "Esegui qBittorrent." LangString launch_qbt ${LANG_ITALIAN} "Esegui qBittorrent"
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions." ;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
LangString inst_requires_64bit ${LANG_ITALIAN} "This installer works only in 64-bit Windows versions." LangString inst_requires_64bit ${LANG_ITALIAN} "Questo installer di qBittorrent funziona solo con Windows a 64bit."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7." ;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_ITALIAN} "This qBittorrent version requires at least Windows 7." LangString inst_requires_win7 ${LANG_ITALIAN} "Questa versione di qBittorrent richiede Windows 7 o versioni successive."
;------------------------------------ ;------------------------------------
@@ -52,7 +52,7 @@ LangString remove_firewallinfo ${LANG_ITALIAN} "Rimozione regola dal firewall di
;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data" ;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data"
LangString remove_cache ${LANG_ITALIAN} "Rimuovi torrent e dati nella cache" LangString remove_cache ${LANG_ITALIAN} "Rimuovi torrent e dati nella cache"
;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling." ;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling."
LangString uninst_warning ${LANG_ITALIAN} "qBittorrent è in esecuzione. Chiudi l'applicazione prima della disinstallazione." LangString uninst_warning ${LANG_ITALIAN} "qBittorrent è in esecuzione.%n%nChiudi qBittorrent prima della disinstallazione."
;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:" ;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:"
LangString uninst_tor_warn ${LANG_ITALIAN} "Associazione file .torrent non rimossa. File associati con:" LangString uninst_tor_warn ${LANG_ITALIAN} "Associazione file .torrent non rimossa. File associati con:"
;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:" ;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_KOREAN} "qBittorrent (required)" LangString inst_qbt_req ${LANG_KOREAN} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_KURDISH} "qBittorrent (required)" LangString inst_qbt_req ${LANG_KURDISH} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_LATVIAN} "qBittorrent (required)" LangString inst_qbt_req ${LANG_LATVIAN} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_LITHUANIAN} "qBittorrent (reikalingas)" LangString inst_qbt_req ${LANG_LITHUANIAN} "qBittorrent (reikalingas)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_LUXEMBOURGISH} "qBittorrent (required)" LangString inst_qbt_req ${LANG_LUXEMBOURGISH} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_MACEDONIAN} "qBittorrent (required)" LangString inst_qbt_req ${LANG_MACEDONIAN} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_MALAY} "qBittorrent (required)" LangString inst_qbt_req ${LANG_MALAY} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_MONGOLIAN} "qBittorrent (required)" LangString inst_qbt_req ${LANG_MONGOLIAN} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_NORWEGIAN} "qBittorrent (kreves)" LangString inst_qbt_req ${LANG_NORWEGIAN} "qBittorrent (kreves)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_NORWEGIANNYNORSK} "qBittorrent (required)" LangString inst_qbt_req ${LANG_NORWEGIANNYNORSK} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_POLISH} "qBittorrent (required)" LangString inst_qbt_req ${LANG_POLISH} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_PORTUGUESE} "qBittorrent (obrigatório)" LangString inst_qbt_req ${LANG_PORTUGUESE} "qBittorrent (obrigatório)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_PORTUGUESEBR} "qBittorrent (requerido)" LangString inst_qbt_req ${LANG_PORTUGUESEBR} "qBittorrent (requerido)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_ROMANIAN} "qBittorrent (required)" LangString inst_qbt_req ${LANG_ROMANIAN} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_RUSSIAN} "qBittorrent (обязательно)" LangString inst_qbt_req ${LANG_RUSSIAN} "qBittorrent (обязательно)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_SERBIAN} "qBittorrent (required)" LangString inst_qbt_req ${LANG_SERBIAN} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_SERBIANLATIN} "qBittorrent (required)" LangString inst_qbt_req ${LANG_SERBIANLATIN} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_SIMPCHINESE} "qBittorrent (必要)" LangString inst_qbt_req ${LANG_SIMPCHINESE} "qBittorrent (必要)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_SLOVAK} "qBittorrent (required)" LangString inst_qbt_req ${LANG_SLOVAK} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_SLOVENIAN} "qBittorrent (required)" LangString inst_qbt_req ${LANG_SLOVENIAN} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_SPANISH} "qBittorrent (necesario)" LangString inst_qbt_req ${LANG_SPANISH} "qBittorrent (necesario)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_SPANISHINTERNATIONAL} "qBittorrent (necesario)" LangString inst_qbt_req ${LANG_SPANISHINTERNATIONAL} "qBittorrent (necesario)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_SWEDISH} "qBittorrent (required)" LangString inst_qbt_req ${LANG_SWEDISH} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_THAI} "qBittorrent (required)" LangString inst_qbt_req ${LANG_THAI} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_TRADCHINESE} "qBittorrent (必要)" LangString inst_qbt_req ${LANG_TRADCHINESE} "qBittorrent (必要)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_TURKISH} "qBittorrent (zorunlu)" LangString inst_qbt_req ${LANG_TURKISH} "qBittorrent (zorunlu)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_UKRAINIAN} "qBittorrent (необхідний)" LangString inst_qbt_req ${LANG_UKRAINIAN} "qBittorrent (необхідний)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_UZBEK} "qBittorrent (required)" LangString inst_qbt_req ${LANG_UZBEK} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
;Installer strings ;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_WELSH} "qBittorrent (required)" LangString inst_qbt_req ${LANG_WELSH} "qBittorrent (required)"

View File

@@ -1,4 +1,4 @@
Var uninstallerPath Var uninstallerPath
Section "-hidden" Section "-hidden"

View File

@@ -1,4 +1,4 @@
Unicode true Unicode true
ManifestDPIAware true ManifestDPIAware true
;Compress the header too ;Compress the header too
!packhdr "$%TEMP%\exehead.tmp" 'upx.exe -9 --best --ultra-brute "$%TEMP%\exehead.tmp"' !packhdr "$%TEMP%\exehead.tmp" 'upx.exe -9 --best --ultra-brute "$%TEMP%\exehead.tmp"'
@@ -28,7 +28,7 @@ XPStyle on
!define CSIDL_LOCALAPPDATA '0x1C' ;Local Application Data path !define CSIDL_LOCALAPPDATA '0x1C' ;Local Application Data path
; Program specific ; Program specific
!define PROG_VERSION "4.3.0" !define PROG_VERSION "4.3.1"
!define MUI_FINISHPAGE_RUN !define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun !define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun

View File

@@ -1,4 +1,4 @@
!include options.nsi !include options.nsi
!include translations.nsi !include translations.nsi
!include installer.nsi !include installer.nsi
!include uninstaller.nsi !include uninstaller.nsi

View File

@@ -1,4 +1,4 @@
;Nsis translations ;Nsis translations
!insertmacro MUI_LANGUAGE "English" !insertmacro MUI_LANGUAGE "English"
!insertmacro MUI_LANGUAGE "Afrikaans" !insertmacro MUI_LANGUAGE "Afrikaans"

View File

@@ -1,4 +1,4 @@
Section "un.$(remove_files)" ;"un.Remove files" Section "un.$(remove_files)" ;"un.Remove files"
SectionIn RO SectionIn RO
; Remove files and uninstaller ; Remove files and uninstaller

View File

@@ -181,12 +181,14 @@ Application::Application(int &argc, char **argv)
m_fileLogger = new FileLogger(fileLoggerPath(), isFileLoggerBackup(), fileLoggerMaxSize(), isFileLoggerDeleteOld(), fileLoggerAge(), static_cast<FileLogger::FileLogAgeType>(fileLoggerAgeType())); m_fileLogger = new FileLogger(fileLoggerPath(), isFileLoggerBackup(), fileLoggerMaxSize(), isFileLoggerDeleteOld(), fileLoggerAge(), static_cast<FileLogger::FileLogAgeType>(fileLoggerAgeType()));
Logger::instance()->addMessage(tr("qBittorrent %1 started", "qBittorrent v3.2.0alpha started").arg(QBT_VERSION)); Logger::instance()->addMessage(tr("qBittorrent %1 started", "qBittorrent v3.2.0alpha started").arg(QBT_VERSION));
if (portableModeEnabled) { if (portableModeEnabled)
{
Logger::instance()->addMessage(tr("Running in portable mode. Auto detected profile folder at: %1").arg(profileDir)); Logger::instance()->addMessage(tr("Running in portable mode. Auto detected profile folder at: %1").arg(profileDir));
if (m_commandLineArgs.relativeFastresumePaths) if (m_commandLineArgs.relativeFastresumePaths)
Logger::instance()->addMessage(tr("Redundant command line flag detected: \"%1\". Portable mode implies relative fastresume.").arg("--relative-fastresume"), Log::WARNING); // to avoid translating the `--relative-fastresume` string Logger::instance()->addMessage(tr("Redundant command line flag detected: \"%1\". Portable mode implies relative fastresume.").arg("--relative-fastresume"), Log::WARNING); // to avoid translating the `--relative-fastresume` string
} }
else { else
{
Logger::instance()->addMessage(tr("Using config directory: %1").arg(Profile::instance()->location(SpecialFolder::Config))); Logger::instance()->addMessage(tr("Using config directory: %1").arg(Profile::instance()->location(SpecialFolder::Config)));
} }
} }
@@ -361,11 +363,13 @@ void Application::runExternalProgram(const BitTorrent::TorrentHandle *torrent) c
proc.setArguments(argList); proc.setArguments(argList);
proc.setCreateProcessArgumentsModifier([](QProcess::CreateProcessArguments *args) proc.setCreateProcessArgumentsModifier([](QProcess::CreateProcessArguments *args)
{ {
if (Preferences::instance()->isAutoRunConsoleEnabled()) { if (Preferences::instance()->isAutoRunConsoleEnabled())
{
args->flags |= CREATE_NEW_CONSOLE; args->flags |= CREATE_NEW_CONSOLE;
args->flags &= ~(CREATE_NO_WINDOW | DETACHED_PROCESS); args->flags &= ~(CREATE_NO_WINDOW | DETACHED_PROCESS);
} }
else { else
{
args->flags |= CREATE_NO_WINDOW; args->flags |= CREATE_NO_WINDOW;
args->flags &= ~(CREATE_NEW_CONSOLE | DETACHED_PROCESS); args->flags &= ~(CREATE_NEW_CONSOLE | DETACHED_PROCESS);
} }
@@ -428,7 +432,8 @@ void Application::torrentFinished(BitTorrent::TorrentHandle *const torrent)
runExternalProgram(torrent); runExternalProgram(torrent);
// Mail notification // Mail notification
if (pref->isMailNotificationEnabled()) { if (pref->isMailNotificationEnabled())
{
Logger::instance()->addMessage(tr("Torrent: %1, sending mail notification").arg(torrent->name())); Logger::instance()->addMessage(tr("Torrent: %1, sending mail notification").arg(torrent->name()));
sendNotificationEmail(torrent); sendNotificationEmail(torrent);
} }
@@ -455,16 +460,19 @@ void Application::allTorrentsFinished()
#ifndef DISABLE_GUI #ifndef DISABLE_GUI
// ask confirm // ask confirm
if ((action == ShutdownDialogAction::Exit) && (pref->dontConfirmAutoExit())) { if ((action == ShutdownDialogAction::Exit) && (pref->dontConfirmAutoExit()))
{
// do nothing & skip confirm // do nothing & skip confirm
} }
else { else
{
if (!ShutdownConfirmDialog::askForConfirmation(m_window, action)) return; if (!ShutdownConfirmDialog::askForConfirmation(m_window, action)) return;
} }
#endif // DISABLE_GUI #endif // DISABLE_GUI
// Actually shut down // Actually shut down
if (action != ShutdownDialogAction::Exit) { if (action != ShutdownDialogAction::Exit)
{
qDebug("Preparing for auto-shutdown because all downloads are complete!"); qDebug("Preparing for auto-shutdown because all downloads are complete!");
// Disabling it for next time // Disabling it for next time
pref->setShutdownWhenDownloadsComplete(false); pref->setShutdownWhenDownloadsComplete(false);
@@ -490,7 +498,8 @@ bool Application::sendParams(const QStringList &params)
void Application::processParams(const QStringList &params) void Application::processParams(const QStringList &params)
{ {
#ifndef DISABLE_GUI #ifndef DISABLE_GUI
if (params.isEmpty()) { if (params.isEmpty())
{
m_window->activate(); // show UI m_window->activate(); // show UI
return; return;
} }
@@ -498,42 +507,50 @@ void Application::processParams(const QStringList &params)
BitTorrent::AddTorrentParams torrentParams; BitTorrent::AddTorrentParams torrentParams;
TriStateBool skipTorrentDialog; TriStateBool skipTorrentDialog;
for (QString param : params) { for (QString param : params)
{
param = param.trimmed(); param = param.trimmed();
// Process strings indicating options specified by the user. // Process strings indicating options specified by the user.
if (param.startsWith(QLatin1String("@savePath="))) { if (param.startsWith(QLatin1String("@savePath=")))
{
torrentParams.savePath = param.mid(10); torrentParams.savePath = param.mid(10);
continue; continue;
} }
if (param.startsWith(QLatin1String("@addPaused="))) { if (param.startsWith(QLatin1String("@addPaused=")))
{
torrentParams.addPaused = param.midRef(11).toInt() ? TriStateBool::True : TriStateBool::False; torrentParams.addPaused = param.midRef(11).toInt() ? TriStateBool::True : TriStateBool::False;
continue; continue;
} }
if (param == QLatin1String("@skipChecking")) { if (param == QLatin1String("@skipChecking"))
{
torrentParams.skipChecking = true; torrentParams.skipChecking = true;
continue; continue;
} }
if (param.startsWith(QLatin1String("@category="))) { if (param.startsWith(QLatin1String("@category=")))
{
torrentParams.category = param.mid(10); torrentParams.category = param.mid(10);
continue; continue;
} }
if (param == QLatin1String("@sequential")) { if (param == QLatin1String("@sequential"))
{
torrentParams.sequential = true; torrentParams.sequential = true;
continue; continue;
} }
if (param == QLatin1String("@firstLastPiecePriority")) { if (param == QLatin1String("@firstLastPiecePriority"))
{
torrentParams.firstLastPiecePriority = true; torrentParams.firstLastPiecePriority = true;
continue; continue;
} }
if (param.startsWith(QLatin1String("@skipDialog="))) { if (param.startsWith(QLatin1String("@skipDialog=")))
{
skipTorrentDialog = param.midRef(12).toInt() ? TriStateBool::True : TriStateBool::False; skipTorrentDialog = param.midRef(12).toInt() ? TriStateBool::True : TriStateBool::False;
continue; continue;
} }
@@ -561,7 +578,8 @@ int Application::exec(const QStringList &params)
Net::DownloadManager::initInstance(); Net::DownloadManager::initInstance();
IconProvider::initInstance(); IconProvider::initInstance();
try { try
{
BitTorrent::Session::initInstance(); BitTorrent::Session::initInstance();
connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentFinished, this, &Application::torrentFinished); connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentFinished, this, &Application::torrentFinished);
connect(BitTorrent::Session::instance(), &BitTorrent::Session::allTorrentsFinished, this, &Application::allTorrentsFinished, Qt::QueuedConnection); connect(BitTorrent::Session::instance(), &BitTorrent::Session::allTorrentsFinished, this, &Application::allTorrentsFinished, Qt::QueuedConnection);
@@ -581,7 +599,8 @@ int Application::exec(const QStringList &params)
new RSS::Session; // create RSS::Session singleton new RSS::Session; // create RSS::Session singleton
new RSS::AutoDownloader; // create RSS::AutoDownloader singleton new RSS::AutoDownloader; // create RSS::AutoDownloader singleton
} }
catch (const RuntimeError &err) { catch (const RuntimeError &err)
{
#ifdef DISABLE_GUI #ifdef DISABLE_GUI
fprintf(stderr, "%s", err.what()); fprintf(stderr, "%s", err.what());
#else #else
@@ -605,7 +624,8 @@ int Application::exec(const QStringList &params)
.arg(QString("http://localhost:") + QString::number(pref->getWebUiPort())) + '\n'; .arg(QString("http://localhost:") + QString::number(pref->getWebUiPort())) + '\n';
printf("%s", qUtf8Printable(mesg)); printf("%s", qUtf8Printable(mesg));
if (pref->getWebUIPassword() == "ARQ77eY1NUZaQsuDHbIMCA==:0WMRkYTUWVT9wVvdDtHAjU9b3b7uB8NR1Gur2hmQCvCDpm39Q+PsJRJPaCU51dEiz+dTzh8qbPsL8WkFljQYFQ==") { if (pref->getWebUIPassword() == "ARQ77eY1NUZaQsuDHbIMCA==:0WMRkYTUWVT9wVvdDtHAjU9b3b7uB8NR1Gur2hmQCvCDpm39Q+PsJRJPaCU51dEiz+dTzh8qbPsL8WkFljQYFQ==")
{
const QString warning = tr("The Web UI administrator username is: %1").arg(pref->getWebUiUsername()) + '\n' const QString warning = tr("The Web UI administrator username is: %1").arg(pref->getWebUiUsername()) + '\n'
+ tr("The Web UI administrator password is still the default one: %1").arg("adminadmin") + '\n' + tr("The Web UI administrator password is still the default one: %1").arg("adminadmin") + '\n'
+ tr("This is a security risk, please consider changing your password from program preferences.") + '\n'; + tr("This is a security risk, please consider changing your password from program preferences.") + '\n';
@@ -623,7 +643,8 @@ int Application::exec(const QStringList &params)
BitTorrent::Session::instance()->startUpTorrents(); BitTorrent::Session::instance()->startUpTorrents();
m_paramsQueue = params + m_paramsQueue; m_paramsQueue = params + m_paramsQueue;
if (!m_paramsQueue.isEmpty()) { if (!m_paramsQueue.isEmpty())
{
processParams(m_paramsQueue); processParams(m_paramsQueue);
m_paramsQueue.clear(); m_paramsQueue.clear();
} }
@@ -639,7 +660,8 @@ bool Application::isRunning()
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
bool Application::event(QEvent *ev) bool Application::event(QEvent *ev)
{ {
if (ev->type() == QEvent::FileOpen) { if (ev->type() == QEvent::FileOpen)
{
QString path = static_cast<QFileOpenEvent *>(ev)->file(); QString path = static_cast<QFileOpenEvent *>(ev)->file();
if (path.isEmpty()) if (path.isEmpty())
// Get the url instead // Get the url instead
@@ -651,7 +673,8 @@ bool Application::event(QEvent *ev)
m_paramsQueue.append(path); m_paramsQueue.append(path);
return true; return true;
} }
else { else
{
return BaseApplication::event(ev); return BaseApplication::event(ev);
} }
} }
@@ -679,11 +702,13 @@ void Application::initializeTranslation()
installTranslator(&m_translator); installTranslator(&m_translator);
#ifndef DISABLE_GUI #ifndef DISABLE_GUI
if (localeStr.startsWith("ar") || localeStr.startsWith("he")) { if (localeStr.startsWith("ar") || localeStr.startsWith("he"))
{
qDebug("Right to Left mode"); qDebug("Right to Left mode");
setLayoutDirection(Qt::RightToLeft); setLayoutDirection(Qt::RightToLeft);
} }
else { else
{
setLayoutDirection(Qt::LeftToRight); setLayoutDirection(Qt::LeftToRight);
} }
#endif #endif
@@ -725,7 +750,8 @@ void Application::cleanup()
return; return;
#ifndef DISABLE_GUI #ifndef DISABLE_GUI
if (m_window) { if (m_window)
{
// Hide the window and don't leave it on screen as // Hide the window and don't leave it on screen as
// unresponsive. Also for Windows take the WinId // unresponsive. Also for Windows take the WinId
// after it's hidden, because hide() may cause a // after it's hidden, because hide() may cause a
@@ -769,7 +795,8 @@ void Application::cleanup()
Utils::Fs::removeDirRecursive(Utils::Fs::tempPath()); Utils::Fs::removeDirRecursive(Utils::Fs::tempPath());
#ifndef DISABLE_GUI #ifndef DISABLE_GUI
if (m_window) { if (m_window)
{
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
::ShutdownBlockReasonDestroy(reinterpret_cast<HWND>(m_window->effectiveWinId())); ::ShutdownBlockReasonDestroy(reinterpret_cast<HWND>(m_window->effectiveWinId()));
#endif // Q_OS_WIN #endif // Q_OS_WIN
@@ -780,7 +807,8 @@ void Application::cleanup()
Profile::freeInstance(); Profile::freeInstance();
if (m_shutdownAct != ShutdownDialogAction::Exit) { if (m_shutdownAct != ShutdownDialogAction::Exit)
{
qDebug() << "Sending computer shutdown/suspend/hibernate signal..."; qDebug() << "Sending computer shutdown/suspend/hibernate signal...";
Utils::Misc::shutdownComputer(m_shutdownAct); Utils::Misc::shutdownComputer(m_shutdownAct);
} }

View File

@@ -46,16 +46,20 @@ ApplicationInstanceManager::ApplicationInstanceManager(const QString &appId, QOb
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
auto sharedMem = new QSharedMemory {appId + QLatin1String {"-shared-memory-key"}, this}; auto sharedMem = new QSharedMemory {appId + QLatin1String {"-shared-memory-key"}, this};
if (m_isFirstInstance) { if (m_isFirstInstance)
{
// First instance creates shared memory and store PID // First instance creates shared memory and store PID
if (sharedMem->create(sizeof(DWORD)) && sharedMem->lock()) { if (sharedMem->create(sizeof(DWORD)) && sharedMem->lock())
{
*(static_cast<DWORD *>(sharedMem->data())) = ::GetCurrentProcessId(); *(static_cast<DWORD *>(sharedMem->data())) = ::GetCurrentProcessId();
sharedMem->unlock(); sharedMem->unlock();
} }
} }
else { else
{
// Later instances attach to shared memory and retrieve PID // Later instances attach to shared memory and retrieve PID
if (sharedMem->attach() && sharedMem->lock()) { if (sharedMem->attach() && sharedMem->lock())
{
::AllowSetForegroundWindow(*(static_cast<DWORD *>(sharedMem->data()))); ::AllowSetForegroundWindow(*(static_cast<DWORD *>(sharedMem->data())));
sharedMem->unlock(); sharedMem->unlock();
} }

View File

@@ -217,7 +217,8 @@ namespace
bool ok; bool ok;
int res = val.toInt(&ok); int res = val.toInt(&ok);
if (!ok) { if (!ok)
{
qDebug() << QObject::tr("Expected integer number in environment variable '%1', but got '%2'") qDebug() << QObject::tr("Expected integer number in environment variable '%1', but got '%2'")
.arg(envVarName(), val); .arg(envVarName(), val);
return defaultValue; return defaultValue;
@@ -257,16 +258,20 @@ namespace
{ {
QStringList parts = arg.split(QLatin1Char('=')); QStringList parts = arg.split(QLatin1Char('='));
if (parts.size() == 1) { if (parts.size() == 1)
{
return TriStateBool(m_defaultValue); return TriStateBool(m_defaultValue);
} }
if (parts.size() == 2) { if (parts.size() == 2)
{
QString val = parts[1]; QString val = parts[1];
if ((val.toUpper() == QLatin1String("TRUE")) || (val == QLatin1String("1"))) { if ((val.toUpper() == QLatin1String("TRUE")) || (val == QLatin1String("1")))
{
return TriStateBool::True; return TriStateBool::True;
} }
if ((val.toUpper() == QLatin1String("FALSE")) || (val == QLatin1String("0"))) { if ((val.toUpper() == QLatin1String("FALSE")) || (val == QLatin1String("0")))
{
return TriStateBool::False; return TriStateBool::False;
} }
} }
@@ -281,16 +286,20 @@ namespace
{ {
const QString val = env.value(envVarName(), "-1"); const QString val = env.value(envVarName(), "-1");
if (val.isEmpty()) { if (val.isEmpty())
{
return TriStateBool(m_defaultValue); return TriStateBool(m_defaultValue);
} }
if (val == QLatin1String("-1")) { if (val == QLatin1String("-1"))
{
return TriStateBool::Undefined; return TriStateBool::Undefined;
} }
if ((val.toUpper() == QLatin1String("TRUE")) || (val == QLatin1String("1"))) { if ((val.toUpper() == QLatin1String("TRUE")) || (val == QLatin1String("1")))
{
return TriStateBool::True; return TriStateBool::True;
} }
if ((val.toUpper() == QLatin1String("FALSE")) || (val == QLatin1String("0"))) { if ((val.toUpper() == QLatin1String("FALSE")) || (val == QLatin1String("0")))
{
return TriStateBool::False; return TriStateBool::False;
} }
@@ -365,10 +374,12 @@ QStringList QBtCommandLineParameters::paramList() const
if (!savePath.isEmpty()) if (!savePath.isEmpty())
result.append(QLatin1String("@savePath=") + savePath); result.append(QLatin1String("@savePath=") + savePath);
if (addPaused == TriStateBool::True) { if (addPaused == TriStateBool::True)
{
result.append(QLatin1String("@addPaused=1")); result.append(QLatin1String("@addPaused=1"));
} }
else if (addPaused == TriStateBool::False) { else if (addPaused == TriStateBool::False)
{
result.append(QLatin1String("@addPaused=0")); result.append(QLatin1String("@addPaused=0"));
} }
@@ -384,10 +395,12 @@ QStringList QBtCommandLineParameters::paramList() const
if (firstLastPiecePriority) if (firstLastPiecePriority)
result.append(QLatin1String("@firstLastPiecePriority")); result.append(QLatin1String("@firstLastPiecePriority"));
if (skipDialog == TriStateBool::True) { if (skipDialog == TriStateBool::True)
{
result.append(QLatin1String("@skipDialog=1")); result.append(QLatin1String("@skipDialog=1"));
} }
else if (skipDialog == TriStateBool::False) { else if (skipDialog == TriStateBool::False)
{
result.append(QLatin1String("@skipDialog=0")); result.append(QLatin1String("@skipDialog=0"));
} }
@@ -399,72 +412,91 @@ QBtCommandLineParameters parseCommandLine(const QStringList &args)
{ {
QBtCommandLineParameters result {QProcessEnvironment::systemEnvironment()}; QBtCommandLineParameters result {QProcessEnvironment::systemEnvironment()};
for (int i = 1; i < args.count(); ++i) { for (int i = 1; i < args.count(); ++i)
{
const QString &arg = args[i]; const QString &arg = args[i];
if ((arg.startsWith("--") && !arg.endsWith(".torrent")) if ((arg.startsWith("--") && !arg.endsWith(".torrent"))
|| (arg.startsWith('-') && (arg.size() == 2))) { || (arg.startsWith('-') && (arg.size() == 2)))
{
// Parse known parameters // Parse known parameters
if (arg == SHOW_HELP_OPTION) { if (arg == SHOW_HELP_OPTION)
{
result.showHelp = true; result.showHelp = true;
} }
#if !defined(Q_OS_WIN) || defined(DISABLE_GUI) #if !defined(Q_OS_WIN) || defined(DISABLE_GUI)
else if (arg == SHOW_VERSION_OPTION) { else if (arg == SHOW_VERSION_OPTION)
{
result.showVersion = true; result.showVersion = true;
} }
#endif #endif
else if (arg == WEBUI_PORT_OPTION) { else if (arg == WEBUI_PORT_OPTION)
{
result.webUiPort = WEBUI_PORT_OPTION.value(arg); result.webUiPort = WEBUI_PORT_OPTION.value(arg);
if ((result.webUiPort < 1) || (result.webUiPort > 65535)) if ((result.webUiPort < 1) || (result.webUiPort > 65535))
throw CommandLineParameterError(QObject::tr("%1 must specify a valid port (1 to 65535).") throw CommandLineParameterError(QObject::tr("%1 must specify a valid port (1 to 65535).")
.arg(QLatin1String("--webui-port"))); .arg(QLatin1String("--webui-port")));
} }
#ifndef DISABLE_GUI #ifndef DISABLE_GUI
else if (arg == NO_SPLASH_OPTION) { else if (arg == NO_SPLASH_OPTION)
{
result.noSplash = true; result.noSplash = true;
} }
#elif !defined(Q_OS_WIN) #elif !defined(Q_OS_WIN)
else if (arg == DAEMON_OPTION) { else if (arg == DAEMON_OPTION)
{
result.shouldDaemonize = true; result.shouldDaemonize = true;
} }
#endif #endif
else if (arg == PROFILE_OPTION) { else if (arg == PROFILE_OPTION)
{
result.profileDir = PROFILE_OPTION.value(arg); result.profileDir = PROFILE_OPTION.value(arg);
} }
else if (arg == RELATIVE_FASTRESUME) { else if (arg == RELATIVE_FASTRESUME)
{
result.relativeFastresumePaths = true; result.relativeFastresumePaths = true;
} }
else if (arg == CONFIGURATION_OPTION) { else if (arg == CONFIGURATION_OPTION)
{
result.configurationName = CONFIGURATION_OPTION.value(arg); result.configurationName = CONFIGURATION_OPTION.value(arg);
} }
else if (arg == SAVE_PATH_OPTION) { else if (arg == SAVE_PATH_OPTION)
{
result.savePath = SAVE_PATH_OPTION.value(arg); result.savePath = SAVE_PATH_OPTION.value(arg);
} }
else if (arg == PAUSED_OPTION) { else if (arg == PAUSED_OPTION)
{
result.addPaused = PAUSED_OPTION.value(arg); result.addPaused = PAUSED_OPTION.value(arg);
} }
else if (arg == SKIP_HASH_CHECK_OPTION) { else if (arg == SKIP_HASH_CHECK_OPTION)
{
result.skipChecking = true; result.skipChecking = true;
} }
else if (arg == CATEGORY_OPTION) { else if (arg == CATEGORY_OPTION)
{
result.category = CATEGORY_OPTION.value(arg); result.category = CATEGORY_OPTION.value(arg);
} }
else if (arg == SEQUENTIAL_OPTION) { else if (arg == SEQUENTIAL_OPTION)
{
result.sequential = true; result.sequential = true;
} }
else if (arg == FIRST_AND_LAST_OPTION) { else if (arg == FIRST_AND_LAST_OPTION)
{
result.firstLastPiecePriority = true; result.firstLastPiecePriority = true;
} }
else if (arg == SKIP_DIALOG_OPTION) { else if (arg == SKIP_DIALOG_OPTION)
{
result.skipDialog = SKIP_DIALOG_OPTION.value(arg); result.skipDialog = SKIP_DIALOG_OPTION.value(arg);
} }
else { else
{
// Unknown argument // Unknown argument
result.unknownParameter = arg; result.unknownParameter = arg;
break; break;
} }
} }
else { else
{
QFileInfo torrentPath; QFileInfo torrentPath;
torrentPath.setFile(arg); torrentPath.setFile(arg);
@@ -495,11 +527,14 @@ QString wrapText(const QString &text, int initialIndentation = USAGE_TEXT_COLUMN
QStringList lines = {words.first()}; QStringList lines = {words.first()};
int currentLineMaxLength = wrapAtColumn - initialIndentation; int currentLineMaxLength = wrapAtColumn - initialIndentation;
for (const QString &word : asConst(words.mid(1))) { for (const QString &word : asConst(words.mid(1)))
if (lines.last().length() + word.length() + 1 < currentLineMaxLength) { {
if (lines.last().length() + word.length() + 1 < currentLineMaxLength)
{
lines.last().append(' ' + word); lines.last().append(' ' + word);
} }
else { else
{
lines.append(QString(initialIndentation, ' ') + word); lines.append(QString(initialIndentation, ' ') + word);
currentLineMaxLength = wrapAtColumn; currentLineMaxLength = wrapAtColumn;
} }

View File

@@ -73,7 +73,8 @@ void FileLogger::changePath(const QString &newPath)
dir.mkpath(newPath); dir.mkpath(newPath);
const QString tmpPath = dir.absoluteFilePath("qbittorrent.log"); const QString tmpPath = dir.absoluteFilePath("qbittorrent.log");
if (tmpPath != m_path) { if (tmpPath != m_path)
{
m_path = tmpPath; m_path = tmpPath;
closeLogFile(); closeLogFile();
@@ -89,9 +90,11 @@ void FileLogger::deleteOld(const int age, const FileLogAgeType ageType)
const QFileInfoList fileList = dir.entryInfoList(QStringList("qbittorrent.log.bak*") const QFileInfoList fileList = dir.entryInfoList(QStringList("qbittorrent.log.bak*")
, (QDir::Files | QDir::Writable), (QDir::Time | QDir::Reversed)); , (QDir::Files | QDir::Writable), (QDir::Time | QDir::Reversed));
for (const QFileInfo &file : fileList) { for (const QFileInfo &file : fileList)
{
QDateTime modificationDate = file.lastModified(); QDateTime modificationDate = file.lastModified();
switch (ageType) { switch (ageType)
{
case DAYS: case DAYS:
modificationDate = modificationDate.addDays(age); modificationDate = modificationDate.addDays(age);
break; break;
@@ -124,7 +127,8 @@ void FileLogger::addLogMessage(const Log::Msg &msg)
QTextStream stream(&m_logFile); QTextStream stream(&m_logFile);
stream.setCodec("UTF-8"); stream.setCodec("UTF-8");
switch (msg.type) { switch (msg.type)
{
case Log::INFO: case Log::INFO:
stream << "(I) "; stream << "(I) ";
break; break;
@@ -140,12 +144,14 @@ void FileLogger::addLogMessage(const Log::Msg &msg)
stream << QDateTime::fromMSecsSinceEpoch(msg.timestamp).toString(Qt::ISODate) << " - " << msg.message << '\n'; stream << QDateTime::fromMSecsSinceEpoch(msg.timestamp).toString(Qt::ISODate) << " - " << msg.message << '\n';
if (m_backup && (m_logFile.size() >= m_maxSize)) { if (m_backup && (m_logFile.size() >= m_maxSize))
{
closeLogFile(); closeLogFile();
int counter = 0; int counter = 0;
QString backupLogFilename = m_path + ".bak"; QString backupLogFilename = m_path + ".bak";
while (QFile::exists(backupLogFilename)) { while (QFile::exists(backupLogFilename))
{
++counter; ++counter;
backupLogFilename = m_path + ".bak" + QString::number(counter); backupLogFilename = m_path + ".bak" + QString::number(counter);
} }
@@ -153,7 +159,8 @@ void FileLogger::addLogMessage(const Log::Msg &msg)
QFile::rename(m_path, backupLogFilename); QFile::rename(m_path, backupLogFilename);
openLogFile(); openLogFile();
} }
else { else
{
if (!m_flusher.isActive()) if (!m_flusher.isActive())
m_flusher.start(); m_flusher.start();
} }
@@ -168,7 +175,8 @@ void FileLogger::flushLog()
void FileLogger::openLogFile() void FileLogger::openLogFile()
{ {
if (!m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text) if (!m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)
|| !m_logFile.setPermissions(QFile::ReadOwner | QFile::WriteOwner)) { || !m_logFile.setPermissions(QFile::ReadOwner | QFile::WriteOwner))
{
m_logFile.close(); m_logFile.close();
LogMsg(tr("An error occurred while trying to open the log file. Logging to file is disabled."), Log::CRITICAL); LogMsg(tr("An error occurred while trying to open the log file. Logging to file is disabled."), Log::CRITICAL);
} }

View File

@@ -92,7 +92,8 @@ void sigNormalHandler(int signum);
void sigAbnormalHandler(int signum); void sigAbnormalHandler(int signum);
#endif #endif
// sys_signame[] is only defined in BSD // sys_signame[] is only defined in BSD
const char *const sysSigName[] = { const char *const sysSigName[] =
{
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
"", "", "SIGINT", "", "SIGILL", "", "SIGABRT_COMPAT", "", "SIGFPE", "", "", "", "SIGINT", "", "SIGILL", "", "SIGABRT_COMPAT", "", "SIGFPE", "",
"", "SIGSEGV", "", "", "", "SIGTERM", "", "", "", "", "", "SIGSEGV", "", "", "", "SIGTERM", "", "", "", "",
@@ -141,19 +142,23 @@ int main(int argc, char *argv[])
Application::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); Application::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif #endif
try { try
{
// Create Application // Create Application
auto app = std::make_unique<Application>(argc, argv); auto app = std::make_unique<Application>(argc, argv);
const QBtCommandLineParameters params = app->commandLineArgs(); const QBtCommandLineParameters params = app->commandLineArgs();
if (!params.unknownParameter.isEmpty()) { if (!params.unknownParameter.isEmpty())
{
throw CommandLineParameterError(QObject::tr("%1 is an unknown command line parameter.", throw CommandLineParameterError(QObject::tr("%1 is an unknown command line parameter.",
"--random-parameter is an unknown command line parameter.") "--random-parameter is an unknown command line parameter.")
.arg(params.unknownParameter)); .arg(params.unknownParameter));
} }
#if !defined(Q_OS_WIN) || defined(DISABLE_GUI) #if !defined(Q_OS_WIN) || defined(DISABLE_GUI)
if (params.showVersion) { if (params.showVersion)
if (isOneArg) { {
if (isOneArg)
{
displayVersion(); displayVersion();
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
@@ -161,8 +166,10 @@ int main(int argc, char *argv[])
.arg(QLatin1String("-v (or --version)"))); .arg(QLatin1String("-v (or --version)")));
} }
#endif #endif
if (params.showHelp) { if (params.showHelp)
if (isOneArg) { {
if (isOneArg)
{
displayUsage(argv[0]); displayUsage(argv[0]);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
@@ -175,7 +182,8 @@ int main(int argc, char *argv[])
fprintf(stderr, "Couldn't set environment variable...\n"); fprintf(stderr, "Couldn't set environment variable...\n");
const bool firstTimeUser = !Preferences::instance()->getAcceptedLegal(); const bool firstTimeUser = !Preferences::instance()->getAcceptedLegal();
if (firstTimeUser) { if (firstTimeUser)
{
#ifndef DISABLE_GUI #ifndef DISABLE_GUI
if (!userAgreesWithLegalNotice()) if (!userAgreesWithLegalNotice())
return EXIT_SUCCESS; return EXIT_SUCCESS;
@@ -195,9 +203,11 @@ int main(int argc, char *argv[])
} }
// Check if qBittorrent is already running for this user // Check if qBittorrent is already running for this user
if (app->isRunning()) { if (app->isRunning())
{
#if defined(DISABLE_GUI) && !defined(Q_OS_WIN) #if defined(DISABLE_GUI) && !defined(Q_OS_WIN)
if (params.shouldDaemonize) { if (params.shouldDaemonize)
{
throw CommandLineParameterError(QObject::tr("You cannot use %1: qBittorrent is already running for this user.") throw CommandLineParameterError(QObject::tr("You cannot use %1: qBittorrent is already running for this user.")
.arg(QLatin1String("-d (or --daemon)"))); .arg(QLatin1String("-d (or --daemon)")));
} }
@@ -242,7 +252,8 @@ int main(int argc, char *argv[])
app->setAttribute(Qt::AA_DontShowIconsInMenus); app->setAttribute(Qt::AA_DontShowIconsInMenus);
#endif #endif
if (!firstTimeUser) { if (!firstTimeUser)
{
handleChangedDefaults(DefaultPreferencesMode::Legacy); handleChangedDefaults(DefaultPreferencesMode::Legacy);
#ifndef DISABLE_GUI #ifndef DISABLE_GUI
@@ -256,21 +267,26 @@ int main(int argc, char *argv[])
&& isatty(fileno(stdout)))) return EXIT_FAILURE; && isatty(fileno(stdout)))) return EXIT_FAILURE;
#endif #endif
} }
else { else
{
handleChangedDefaults(DefaultPreferencesMode::Current); handleChangedDefaults(DefaultPreferencesMode::Current);
} }
#if defined(DISABLE_GUI) && !defined(Q_OS_WIN) #if defined(DISABLE_GUI) && !defined(Q_OS_WIN)
if (params.shouldDaemonize) { if (params.shouldDaemonize)
{
app.reset(); // Destroy current application app.reset(); // Destroy current application
if (daemon(1, 0) == 0) { if (daemon(1, 0) == 0)
{
app = std::make_unique<Application>(argc, argv); app = std::make_unique<Application>(argc, argv);
if (app->isRunning()) { if (app->isRunning())
{
// Another instance had time to start. // Another instance had time to start.
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }
else { else
{
qCritical("Something went wrong while daemonizing, exiting..."); qCritical("Something went wrong while daemonizing, exiting...");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@@ -289,7 +305,8 @@ int main(int argc, char *argv[])
return app->exec(params.paramList()); return app->exec(params.paramList());
} }
catch (const CommandLineParameterError &er) { catch (const CommandLineParameterError &er)
{
displayBadArgMessage(er.messageForUser()); displayBadArgMessage(er.messageForUser());
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@@ -300,10 +317,12 @@ void reportToUser(const char *str)
{ {
const size_t strLen = strlen(str); const size_t strLen = strlen(str);
#ifndef Q_OS_WIN #ifndef Q_OS_WIN
if (write(STDERR_FILENO, str, strLen) < static_cast<ssize_t>(strLen)) { if (write(STDERR_FILENO, str, strLen) < static_cast<ssize_t>(strLen))
{
const auto dummy = write(STDOUT_FILENO, str, strLen); const auto dummy = write(STDOUT_FILENO, str, strLen);
#else #else
if (_write(STDERR_FILENO, str, strLen) < static_cast<ssize_t>(strLen)) { if (_write(STDERR_FILENO, str, strLen) < static_cast<ssize_t>(strLen))
{
const auto dummy = _write(STDOUT_FILENO, str, strLen); const auto dummy = _write(STDOUT_FILENO, str, strLen);
#endif #endif
Q_UNUSED(dummy); Q_UNUSED(dummy);
@@ -405,7 +424,8 @@ bool userAgreesWithLegalNotice()
printf("%s", qUtf8Printable(eula)); printf("%s", qUtf8Printable(eula));
const char ret = getchar(); // Read pressed key const char ret = getchar(); // Read pressed key
if ((ret == 'y') || (ret == 'Y')) { if ((ret == 'y') || (ret == 'Y'))
{
// Save the answer // Save the answer
pref->setAcceptedLegal(true); pref->setAcceptedLegal(true);
return true; return true;
@@ -419,7 +439,8 @@ bool userAgreesWithLegalNotice()
msgBox.show(); // Need to be shown or to moveToCenter does not work msgBox.show(); // Need to be shown or to moveToCenter does not work
msgBox.move(Utils::Gui::screenCenter(&msgBox)); msgBox.move(Utils::Gui::screenCenter(&msgBox));
msgBox.exec(); msgBox.exec();
if (msgBox.clickedButton() == agreeButton) { if (msgBox.clickedButton() == agreeButton)
{
// Save the answer // Save the answer
pref->setAcceptedLegal(true); pref->setAcceptedLegal(true);
return true; return true;

View File

@@ -100,7 +100,8 @@ QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
, id(appId) , id(appId)
{ {
QString prefix = id; QString prefix = id;
if (id.isEmpty()) { if (id.isEmpty())
{
id = QCoreApplication::applicationFilePath(); id = QCoreApplication::applicationFilePath();
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
id = id.toLower(); id = id.toLower();
@@ -143,7 +144,8 @@ bool QtLocalPeer::isClient()
bool res = server->listen(socketName); bool res = server->listen(socketName);
#if defined(Q_OS_UNIX) #if defined(Q_OS_UNIX)
// ### Workaround // ### Workaround
if (!res && server->serverError() == QAbstractSocket::AddressInUseError) { if (!res && server->serverError() == QAbstractSocket::AddressInUseError)
{
QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName); QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName);
res = server->listen(socketName); res = server->listen(socketName);
} }
@@ -161,7 +163,8 @@ bool QtLocalPeer::sendMessage(const QString &message, const int timeout)
QLocalSocket socket; QLocalSocket socket;
bool connOk = false; bool connOk = false;
for(int i = 0; i < 2; i++) { for(int i = 0; i < 2; i++)
{
// Try twice, in case the other instance is just starting up // Try twice, in case the other instance is just starting up
socket.connectToServer(socketName); socket.connectToServer(socketName);
connOk = socket.waitForConnected(timeout/2); connOk = socket.waitForConnected(timeout/2);
@@ -182,7 +185,8 @@ bool QtLocalPeer::sendMessage(const QString &message, const int timeout)
QDataStream ds(&socket); QDataStream ds(&socket);
ds.writeBytes(uMsg.constData(), uMsg.size()); ds.writeBytes(uMsg.constData(), uMsg.size());
bool res = socket.waitForBytesWritten(timeout); bool res = socket.waitForBytesWritten(timeout);
if (res) { if (res)
{
res &= socket.waitForReadyRead(timeout); // wait for ack res &= socket.waitForReadyRead(timeout); // wait for ack
if (res) if (res)
res &= (socket.read(qstrlen(ack)) == ack); res &= (socket.read(qstrlen(ack)) == ack);
@@ -201,8 +205,10 @@ void QtLocalPeer::receiveConnection()
if (!socket) if (!socket)
return; return;
while (true) { while (true)
if (socket->state() == QLocalSocket::UnconnectedState) { {
if (socket->state() == QLocalSocket::UnconnectedState)
{
qWarning("QtLocalPeer: Peer disconnected"); qWarning("QtLocalPeer: Peer disconnected");
delete socket; delete socket;
return; return;
@@ -216,7 +222,8 @@ void QtLocalPeer::receiveConnection()
QByteArray uMsg; QByteArray uMsg;
quint32 remaining; quint32 remaining;
ds >> remaining; ds >> remaining;
if (remaining > 65535) { if (remaining > 65535)
{
// drop suspiciously large data // drop suspiciously large data
delete socket; delete socket;
return; return;
@@ -225,12 +232,14 @@ void QtLocalPeer::receiveConnection()
uMsg.resize(remaining); uMsg.resize(remaining);
int got = 0; int got = 0;
char* uMsgBuf = uMsg.data(); char* uMsgBuf = uMsg.data();
do { do
{
got = ds.readRawData(uMsgBuf, remaining); got = ds.readRawData(uMsgBuf, remaining);
remaining -= got; remaining -= got;
uMsgBuf += got; uMsgBuf += got;
} while (remaining && got >= 0 && socket->waitForReadyRead(2000)); } while (remaining && got >= 0 && socket->waitForReadyRead(2000));
if (got < 0) { if (got < 0)
{
qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData()); qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData());
delete socket; delete socket;
return; return;

View File

@@ -178,8 +178,8 @@ QtLockedFile::LockMode QtLockedFile::lockMode() const
can be locked. can be locked.
If \a block is true, this function will block until the lock is If \a block is true, this function will block until the lock is
aquired. If \a block is false, this function returns \e false acquired. If \a block is false, this function returns \e false
immediately if the lock cannot be aquired. immediately if the lock cannot be acquired.
If this object already has a lock of type \a mode, this function If this object already has a lock of type \a mode, this function
returns \e true immediately. If this object has a lock of a returns \e true immediately. If this object has a lock of a

View File

@@ -22,7 +22,8 @@ static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames
// retrieve current stack addresses // retrieve current stack addresses
int addrlen = backtrace(addrlist.data(), addrlist.size()); int addrlen = backtrace(addrlist.data(), addrlist.size());
if (addrlen == 0) { if (addrlen == 0)
{
fprintf(out, " <empty, possibly corrupt>\n"); fprintf(out, " <empty, possibly corrupt>\n");
return; return;
} }
@@ -38,27 +39,33 @@ static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames
int functionNamesFound = 0; int functionNamesFound = 0;
// iterate over the returned symbol lines. skip the first, it is the // iterate over the returned symbol lines. skip the first, it is the
// address of this function. // address of this function.
for (int i = 2; i < addrlen; i++) { for (int i = 2; i < addrlen; i++)
{
char *begin_name = 0, *begin_offset = 0, *end_offset = 0; char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
// find parentheses and +address offset surrounding the mangled name: // find parentheses and +address offset surrounding the mangled name:
// ./module(function+0x15c) [0x8048a6d] // ./module(function+0x15c) [0x8048a6d]
// fprintf(out, "%s TT\n", symbollist[i]); // fprintf(out, "%s TT\n", symbollist[i]);
for (char *p = symbollist[i]; *p; ++p) { for (char *p = symbollist[i]; *p; ++p)
if (*p == '(') { {
if (*p == '(')
{
begin_name = p; begin_name = p;
} }
else if (*p == '+') { else if (*p == '+')
{
begin_offset = p; begin_offset = p;
} }
else if ((*p == ')') && begin_offset) { else if ((*p == ')') && begin_offset)
{
end_offset = p; end_offset = p;
break; break;
} }
} }
if (begin_name && begin_offset && end_offset if (begin_name && begin_offset && end_offset
&& (begin_name < begin_offset)) { && (begin_name < begin_offset))
{
*begin_name++ = '\0'; *begin_name++ = '\0';
*begin_offset++ = '\0'; *begin_offset++ = '\0';
*end_offset = '\0'; *end_offset = '\0';
@@ -70,12 +77,14 @@ static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames
int status; int status;
char *ret = abi::__cxa_demangle(begin_name, char *ret = abi::__cxa_demangle(begin_name,
funcname, &funcnamesize, &status); funcname, &funcnamesize, &status);
if (status == 0) { if (status == 0)
{
funcname = ret; // use possibly realloc()-ed string funcname = ret; // use possibly realloc()-ed string
fprintf(out, " %s : %s+%s %s\n", fprintf(out, " %s : %s+%s %s\n",
symbollist[i], funcname, begin_offset, ++end_offset); symbollist[i], funcname, begin_offset, ++end_offset);
} }
else { else
{
// demangling failed. Output function name as a C function with // demangling failed. Output function name as a C function with
// no arguments. // no arguments.
fprintf(out, " %s : %s()+%s %s\n", fprintf(out, " %s : %s()+%s %s\n",
@@ -83,17 +92,20 @@ static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames
} }
++functionNamesFound; ++functionNamesFound;
} }
else { else
{
// couldn't parse the line? print the whole line. // couldn't parse the line? print the whole line.
fprintf(out, " %s\n", symbollist[i]); fprintf(out, " %s\n", symbollist[i]);
} }
} }
if (!functionNamesFound) { if (!functionNamesFound)
{
fprintf(out, "There were no function names found in the stack trace\n." fprintf(out, "There were no function names found in the stack trace\n."
"Seems like debug symbols are not installed, and the stack trace is useless.\n"); "Seems like debug symbols are not installed, and the stack trace is useless.\n");
} }
if (functionNamesFound < addrlen - 2) { if (functionNamesFound < addrlen - 2)
{
fprintf(out, "Consider installing debug symbols for packages containing files with empty" fprintf(out, "Consider installing debug symbols for packages containing files with empty"
" function names (i.e. empty braces \"()\") to make your stack trace more useful\n"); " function names (i.e. empty braces \"()\") to make your stack trace more useful\n");
} }

View File

@@ -54,7 +54,8 @@ void straceWin::demangle(QString& str)
int status = 0; int status = 0;
size_t outSz = 0; size_t outSz = 0;
char* demangled_name = abi::__cxa_demangle(inStr, 0, &outSz, &status); char* demangled_name = abi::__cxa_demangle(inStr, 0, &outSz, &status);
if (status == 0) { if (status == 0)
{
str = QString::fromLocal8Bit(demangled_name); str = QString::fromLocal8Bit(demangled_name);
if (outSz > 0) if (outSz > 0)
free(demangled_name); free(demangled_name);
@@ -92,7 +93,8 @@ BOOL CALLBACK straceWin::EnumModulesCB(LPCSTR ModuleName, DWORD64 BaseOfDll, PVO
IMAGEHLP_MODULE64 mod; IMAGEHLP_MODULE64 mod;
EnumModulesContext* context = (EnumModulesContext*)UserContext; EnumModulesContext* context = (EnumModulesContext*)UserContext;
mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
if(SymGetModuleInfo64(context->hProcess, BaseOfDll, &mod)) { if(SymGetModuleInfo64(context->hProcess, BaseOfDll, &mod))
{
QString moduleBase = QString::fromLatin1("0x%1").arg(BaseOfDll, 16, 16, QLatin1Char('0')); QString moduleBase = QString::fromLatin1("0x%1").arg(BaseOfDll, 16, 16, QLatin1Char('0'));
QString line = QString::fromLatin1("%1 %2 Image: %3") QString line = QString::fromLatin1("%1 %2 Image: %3")
.arg(mod.ModuleName, -25) .arg(mod.ModuleName, -25)
@@ -101,7 +103,8 @@ BOOL CALLBACK straceWin::EnumModulesCB(LPCSTR ModuleName, DWORD64 BaseOfDll, PVO
context->stream << line << '\n'; context->stream << line << '\n';
QString pdbName(mod.LoadedPdbName); QString pdbName(mod.LoadedPdbName);
if(!pdbName.isEmpty()) { if(!pdbName.isEmpty())
{
QString line2 = QString::fromLatin1("%1 %2") QString line2 = QString::fromLatin1("%1 %2")
.arg("", 35) .arg("", 35)
.arg(pdbName); .arg(pdbName);
@@ -126,7 +129,8 @@ bool straceWin::makeRelativePath(const QString& dir, QString& file)
if (!d.isEmpty() && (d[d.length() - 1] != separator)) if (!d.isEmpty() && (d[d.length() - 1] != separator))
d += separator; d += separator;
if (f.startsWith(d, Qt::CaseInsensitive)) { if (f.startsWith(d, Qt::CaseInsensitive))
{
f.remove(0, d.length()); f.remove(0, d.length());
file.swap(f); file.swap(f);
@@ -142,7 +146,8 @@ QString straceWin::getSourcePathAndLineNumber(HANDLE hProcess, DWORD64 addr)
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
DWORD dwDisplacement = 0; DWORD dwDisplacement = 0;
if (SymGetLineFromAddr64(hProcess, addr, &dwDisplacement, &line)) { if (SymGetLineFromAddr64(hProcess, addr, &dwDisplacement, &line))
{
QString path(line.FileName); QString path(line.FileName);
#if defined STACKTRACE_WIN_PROJECT_PATH || defined STACKTRACE_WIN_MAKEFILE_PATH #if defined STACKTRACE_WIN_PROJECT_PATH || defined STACKTRACE_WIN_MAKEFILE_PATH
@@ -159,7 +164,8 @@ QString straceWin::getSourcePathAndLineNumber(HANDLE hProcess, DWORD64 addr)
#endif #endif
#ifdef STACKTRACE_WIN_MAKEFILE_PATH #ifdef STACKTRACE_WIN_MAKEFILE_PATH
if (!success) { if (!success)
{
QString targetPath(STACKTRACE_WIN_STRING(STACKTRACE_WIN_MAKEFILE_PATH)); QString targetPath(STACKTRACE_WIN_STRING(STACKTRACE_WIN_MAKEFILE_PATH));
makeRelativePath(targetPath, path); makeRelativePath(targetPath, path);
} }
@@ -201,7 +207,8 @@ const QString straceWin::getBacktrace()
: //no input : //no input
: "eax"); : "eax");
#else #else
_asm { _asm
{
Label: Label:
mov [Context.Ebp], ebp; mov [Context.Ebp], ebp;
mov [Context.Esp], esp; mov [Context.Esp], esp;
@@ -269,15 +276,18 @@ const QString straceWin::getBacktrace()
int i = 0; int i = 0;
while(StackWalk64(MachineType, hProcess, hThread, &StackFrame, &Context, NULL, NULL, NULL, NULL)) { while(StackWalk64(MachineType, hProcess, hThread, &StackFrame, &Context, NULL, NULL, NULL, NULL))
{
if(i == 128) if(i == 128)
break; break;
loadHelpStackFrame(ihsf, StackFrame); loadHelpStackFrame(ihsf, StackFrame);
if(StackFrame.AddrPC.Offset != 0) { // Valid frame. if(StackFrame.AddrPC.Offset != 0)
{ // Valid frame.
QString fileName("???"); QString fileName("???");
if(SymGetModuleInfo64(hProcess, ihsf.InstructionOffset, &mod)) { if(SymGetModuleInfo64(hProcess, ihsf.InstructionOffset, &mod))
{
fileName = QString(mod.ImageName); fileName = QString(mod.ImageName);
int slashPos = fileName.lastIndexOf('\\'); int slashPos = fileName.lastIndexOf('\\');
if(slashPos != -1) if(slashPos != -1)
@@ -285,7 +295,8 @@ const QString straceWin::getBacktrace()
} }
QString funcName; QString funcName;
QString sourceFile; QString sourceFile;
if(SymFromAddr(hProcess, ihsf.InstructionOffset, &dwDisplacement, pSymbol)) { if(SymFromAddr(hProcess, ihsf.InstructionOffset, &dwDisplacement, pSymbol))
{
funcName = QString(pSymbol->Name); funcName = QString(pSymbol->Name);
#ifdef __MINGW32__ #ifdef __MINGW32__
demangle(funcName); demangle(funcName);
@@ -295,7 +306,8 @@ const QString straceWin::getBacktrace()
// decrease the query address by one byte to point somewhere in the CALL instruction byte sequence // decrease the query address by one byte to point somewhere in the CALL instruction byte sequence
sourceFile = getSourcePathAndLineNumber(hProcess, ihsf.InstructionOffset - 1); sourceFile = getSourcePathAndLineNumber(hProcess, ihsf.InstructionOffset - 1);
} }
else { else
{
funcName = QString::fromLatin1("0x%1").arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0')); funcName = QString::fromLatin1("0x%1").arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0'));
} }
SymSetContext(hProcess, &ihsf, NULL); SymSetContext(hProcess, &ihsf, NULL);
@@ -325,7 +337,8 @@ const QString straceWin::getBacktrace()
logStream << debugLine << '\n'; logStream << debugLine << '\n';
i++; i++;
} }
else { else
{
break; // we're at the end. break; // we're at the end.
} }
} }

View File

@@ -39,7 +39,8 @@ namespace
{ {
void exportWebUIHttpsFiles() void exportWebUIHttpsFiles()
{ {
const auto migrate = [](const QString &oldKey, const QString &newKey, const QString &savePath) { const auto migrate = [](const QString &oldKey, const QString &newKey, const QString &savePath)
{
SettingsStorage *settingsStorage {SettingsStorage::instance()}; SettingsStorage *settingsStorage {SettingsStorage::instance()};
const QByteArray oldData {settingsStorage->loadValue(oldKey).toByteArray()}; const QByteArray oldData {settingsStorage->loadValue(oldKey).toByteArray()};
const QString newData {settingsStorage->loadValue(newKey).toString()}; const QString newData {settingsStorage->loadValue(newKey).toString()};
@@ -49,11 +50,13 @@ namespace
return; return;
QFile file(savePath); QFile file(savePath);
if (!file.open(QIODevice::WriteOnly)) { if (!file.open(QIODevice::WriteOnly))
{
LogMsg(errorMsgFormat.arg(savePath, file.errorString()) , Log::WARNING); LogMsg(errorMsgFormat.arg(savePath, file.errorString()) , Log::WARNING);
return; return;
} }
if (file.write(oldData) != oldData.size()) { if (file.write(oldData) != oldData.size())
{
file.close(); file.close();
Utils::Fs::forceRemove(savePath); Utils::Fs::forceRemove(savePath);
LogMsg(errorMsgFormat.arg(savePath, QLatin1String("Write incomplete.")) , Log::WARNING); LogMsg(errorMsgFormat.arg(savePath, QLatin1String("Write incomplete.")) , Log::WARNING);
@@ -92,12 +95,14 @@ void handleChangedDefaults(const DefaultPreferencesMode mode)
QVariant current; QVariant current;
}; };
const QVector<DefaultValue> changedDefaults { const QVector<DefaultValue> changedDefaults
{
{QLatin1String {"BitTorrent/Session/QueueingSystemEnabled"}, true, false} {QLatin1String {"BitTorrent/Session/QueueingSystemEnabled"}, true, false}
}; };
SettingsStorage *settingsStorage {SettingsStorage::instance()}; SettingsStorage *settingsStorage {SettingsStorage::instance()};
for (auto it = changedDefaults.cbegin(); it != changedDefaults.cend(); ++it) { for (auto it = changedDefaults.cbegin(); it != changedDefaults.cend(); ++it)
{
if (settingsStorage->loadValue(it->name).isNull()) if (settingsStorage->loadValue(it->name).isNull())
settingsStorage->storeValue(it->name, (mode == DefaultPreferencesMode::Legacy ? it->legacy : it->current)); settingsStorage->storeValue(it->name, (mode == DefaultPreferencesMode::Legacy ? it->legacy : it->current));
} }

View File

@@ -10,6 +10,7 @@ add_library(qbt_base STATIC
bittorrent/downloadpriority.h bittorrent/downloadpriority.h
bittorrent/filterparserthread.h bittorrent/filterparserthread.h
bittorrent/infohash.h bittorrent/infohash.h
bittorrent/ltqhash.h
bittorrent/ltunderlyingtype.h bittorrent/ltunderlyingtype.h
bittorrent/magneturi.h bittorrent/magneturi.h
bittorrent/nativesessionextension.h bittorrent/nativesessionextension.h

View File

@@ -38,7 +38,8 @@ AsyncFileStorage::AsyncFileStorage(const QString &storageFolderPath, QObject *pa
, m_lockFile(m_storageDir.absoluteFilePath(QStringLiteral("storage.lock"))) , m_lockFile(m_storageDir.absoluteFilePath(QStringLiteral("storage.lock")))
{ {
if (!m_storageDir.mkpath(m_storageDir.absolutePath())) if (!m_storageDir.mkpath(m_storageDir.absolutePath()))
throw AsyncFileStorageError {tr("Could not create directory '%1'.") throw AsyncFileStorageError
{tr("Could not create directory '%1'.")
.arg(m_storageDir.absolutePath())}; .arg(m_storageDir.absolutePath())};
// TODO: This folder locking approach does not work for UNIX systems. Implement it. // TODO: This folder locking approach does not work for UNIX systems. Implement it.
@@ -73,9 +74,11 @@ void AsyncFileStorage::store_impl(const QString &fileName, const QByteArray &dat
const QString filePath = m_storageDir.absoluteFilePath(fileName); const QString filePath = m_storageDir.absoluteFilePath(fileName);
QSaveFile file(filePath); QSaveFile file(filePath);
qDebug() << "AsyncFileStorage: Saving data to" << filePath; qDebug() << "AsyncFileStorage: Saving data to" << filePath;
if (file.open(QIODevice::WriteOnly)) { if (file.open(QIODevice::WriteOnly))
{
file.write(data); file.write(data);
if (!file.commit()) { if (!file.commit())
{
qDebug() << "AsyncFileStorage: Failed to save data"; qDebug() << "AsyncFileStorage: Failed to save data";
emit failed(filePath, file.errorString()); emit failed(filePath, file.errorString());
} }

View File

@@ -9,6 +9,7 @@ HEADERS += \
$$PWD/bittorrent/downloadpriority.h \ $$PWD/bittorrent/downloadpriority.h \
$$PWD/bittorrent/filterparserthread.h \ $$PWD/bittorrent/filterparserthread.h \
$$PWD/bittorrent/infohash.h \ $$PWD/bittorrent/infohash.h \
$$PWD/bittorrent/ltqhash.h \
$$PWD/bittorrent/ltunderlyingtype.h \ $$PWD/bittorrent/ltunderlyingtype.h \
$$PWD/bittorrent/magneturi.h \ $$PWD/bittorrent/magneturi.h \
$$PWD/bittorrent/nativesessionextension.h \ $$PWD/bittorrent/nativesessionextension.h \

View File

@@ -65,13 +65,16 @@ bool BandwidthScheduler::isTimeForAlternative() const
const int day = QDate::currentDate().dayOfWeek(); const int day = QDate::currentDate().dayOfWeek();
bool alternative = false; bool alternative = false;
if (start > end) { if (start > end)
{
std::swap(start, end); std::swap(start, end);
alternative = true; alternative = true;
} }
if ((start <= now) && (end >= now)) { if ((start <= now) && (end >= now))
switch (schedulerDays) { {
switch (schedulerDays)
{
case EVERY_DAY: case EVERY_DAY:
alternative = !alternative; alternative = !alternative;
break; break;
@@ -96,7 +99,8 @@ void BandwidthScheduler::onTimeout()
{ {
const bool alternative = isTimeForAlternative(); const bool alternative = isTimeForAlternative();
if (alternative != m_lastAlternative) { if (alternative != m_lastAlternative)
{
m_lastAlternative = alternative; m_lastAlternative = alternative;
emit bandwidthLimitRequested(alternative); emit bandwidthLimitRequested(alternative);
} }

View File

@@ -41,20 +41,21 @@
std::unique_ptr<lt::disk_interface> customDiskIOConstructor( std::unique_ptr<lt::disk_interface> customDiskIOConstructor(
lt::io_context &ioContext, const lt::settings_interface &settings, lt::counters &counters) lt::io_context &ioContext, const lt::settings_interface &settings, lt::counters &counters)
{ {
return std::make_unique<customDiskIOThread>(lt::default_disk_io_constructor(ioContext, settings, counters)); return std::make_unique<CustomDiskIOThread>(lt::default_disk_io_constructor(ioContext, settings, counters));
} }
customDiskIOThread::customDiskIOThread(std::unique_ptr<libtorrent::disk_interface> nativeDiskIOThread) CustomDiskIOThread::CustomDiskIOThread(std::unique_ptr<libtorrent::disk_interface> nativeDiskIOThread)
: m_nativeDiskIO {std::move(nativeDiskIOThread)} : m_nativeDiskIO {std::move(nativeDiskIOThread)}
{ {
} }
lt::storage_holder customDiskIOThread::new_torrent(const lt::storage_params &storageParams, const std::shared_ptr<void> &torrent) lt::storage_holder CustomDiskIOThread::new_torrent(const lt::storage_params &storageParams, const std::shared_ptr<void> &torrent)
{ {
lt::storage_holder storageHolder = m_nativeDiskIO->new_torrent(storageParams, torrent); lt::storage_holder storageHolder = m_nativeDiskIO->new_torrent(storageParams, torrent);
const QString savePath = Utils::Fs::expandPathAbs(QString::fromStdString(storageParams.path)); const QString savePath = Utils::Fs::expandPathAbs(QString::fromStdString(storageParams.path));
m_storageData[storageHolder] = { m_storageData[storageHolder] =
{
savePath savePath
, storageParams.mapped_files ? *storageParams.mapped_files : storageParams.files , storageParams.mapped_files ? *storageParams.mapped_files : storageParams.files
, storageParams.priorities}; , storageParams.priorities};
@@ -62,40 +63,40 @@ lt::storage_holder customDiskIOThread::new_torrent(const lt::storage_params &sto
return storageHolder; return storageHolder;
} }
void customDiskIOThread::remove_torrent(lt::storage_index_t storage) void CustomDiskIOThread::remove_torrent(lt::storage_index_t storage)
{ {
m_nativeDiskIO->remove_torrent(storage); m_nativeDiskIO->remove_torrent(storage);
} }
void customDiskIOThread::async_read(lt::storage_index_t storage, const lt::peer_request &peerRequest void CustomDiskIOThread::async_read(lt::storage_index_t storage, const lt::peer_request &peerRequest
, std::function<void (lt::disk_buffer_holder, const lt::storage_error &)> handler , std::function<void (lt::disk_buffer_holder, const lt::storage_error &)> handler
, lt::disk_job_flags_t flags) , lt::disk_job_flags_t flags)
{ {
m_nativeDiskIO->async_read(storage, peerRequest, std::move(handler), flags); m_nativeDiskIO->async_read(storage, peerRequest, std::move(handler), flags);
} }
bool customDiskIOThread::async_write(lt::storage_index_t storage, const lt::peer_request &peerRequest bool CustomDiskIOThread::async_write(lt::storage_index_t storage, const lt::peer_request &peerRequest
, const char *buf, std::shared_ptr<lt::disk_observer> diskObserver , const char *buf, std::shared_ptr<lt::disk_observer> diskObserver
, std::function<void (const lt::storage_error &)> handler, lt::disk_job_flags_t flags) , std::function<void (const lt::storage_error &)> handler, lt::disk_job_flags_t flags)
{ {
return m_nativeDiskIO->async_write(storage, peerRequest, buf, diskObserver, std::move(handler), flags); return m_nativeDiskIO->async_write(storage, peerRequest, buf, diskObserver, std::move(handler), flags);
} }
void customDiskIOThread::async_hash(lt::storage_index_t storage, lt::piece_index_t piece void CustomDiskIOThread::async_hash(lt::storage_index_t storage, lt::piece_index_t piece
, lt::span<lt::sha256_hash> hash, lt::disk_job_flags_t flags , lt::span<lt::sha256_hash> hash, lt::disk_job_flags_t flags
, std::function<void (lt::piece_index_t, const lt::sha1_hash &, const lt::storage_error &)> handler) , std::function<void (lt::piece_index_t, const lt::sha1_hash &, const lt::storage_error &)> handler)
{ {
m_nativeDiskIO->async_hash(storage, piece, hash, flags, std::move(handler)); m_nativeDiskIO->async_hash(storage, piece, hash, flags, std::move(handler));
} }
void customDiskIOThread::async_hash2(lt::storage_index_t storage, lt::piece_index_t piece void CustomDiskIOThread::async_hash2(lt::storage_index_t storage, lt::piece_index_t piece
, int offset, lt::disk_job_flags_t flags , int offset, lt::disk_job_flags_t flags
, std::function<void (lt::piece_index_t, const lt::sha256_hash &, const lt::storage_error &)> handler) , std::function<void (lt::piece_index_t, const lt::sha256_hash &, const lt::storage_error &)> handler)
{ {
m_nativeDiskIO->async_hash2(storage, piece, offset, flags, std::move(handler)); m_nativeDiskIO->async_hash2(storage, piece, offset, flags, std::move(handler));
} }
void customDiskIOThread::async_move_storage(lt::storage_index_t storage, std::string path, lt::move_flags_t flags void CustomDiskIOThread::async_move_storage(lt::storage_index_t storage, std::string path, lt::move_flags_t flags
, std::function<void (lt::status_t, const std::string &, const lt::storage_error &)> handler) , std::function<void (lt::status_t, const std::string &, const lt::storage_error &)> handler)
{ {
const QString newSavePath {Utils::Fs::expandPathAbs(QString::fromStdString(path))}; const QString newSavePath {Utils::Fs::expandPathAbs(QString::fromStdString(path))};
@@ -113,12 +114,12 @@ void customDiskIOThread::async_move_storage(lt::storage_index_t storage, std::st
}); });
} }
void customDiskIOThread::async_release_files(lt::storage_index_t storage, std::function<void ()> handler) void CustomDiskIOThread::async_release_files(lt::storage_index_t storage, std::function<void ()> handler)
{ {
m_nativeDiskIO->async_release_files(storage, std::move(handler)); m_nativeDiskIO->async_release_files(storage, std::move(handler));
} }
void customDiskIOThread::async_check_files(lt::storage_index_t storage, const lt::add_torrent_params *resume_data void CustomDiskIOThread::async_check_files(lt::storage_index_t storage, const lt::add_torrent_params *resume_data
, lt::aux::vector<std::string, lt::file_index_t> links , lt::aux::vector<std::string, lt::file_index_t> links
, std::function<void (lt::status_t, const lt::storage_error &)> handler) , std::function<void (lt::status_t, const lt::storage_error &)> handler)
{ {
@@ -126,12 +127,12 @@ void customDiskIOThread::async_check_files(lt::storage_index_t storage, const lt
m_nativeDiskIO->async_check_files(storage, resume_data, links, std::move(handler)); m_nativeDiskIO->async_check_files(storage, resume_data, links, std::move(handler));
} }
void customDiskIOThread::async_stop_torrent(lt::storage_index_t storage, std::function<void ()> handler) void CustomDiskIOThread::async_stop_torrent(lt::storage_index_t storage, std::function<void ()> handler)
{ {
m_nativeDiskIO->async_stop_torrent(storage, std::move(handler)); m_nativeDiskIO->async_stop_torrent(storage, std::move(handler));
} }
void customDiskIOThread::async_rename_file(lt::storage_index_t storage, lt::file_index_t index, std::string name void CustomDiskIOThread::async_rename_file(lt::storage_index_t storage, lt::file_index_t index, std::string name
, std::function<void (const std::string &, lt::file_index_t, const lt::storage_error &)> handler) , std::function<void (const std::string &, lt::file_index_t, const lt::storage_error &)> handler)
{ {
m_nativeDiskIO->async_rename_file(storage, index, name m_nativeDiskIO->async_rename_file(storage, index, name
@@ -143,13 +144,13 @@ void customDiskIOThread::async_rename_file(lt::storage_index_t storage, lt::file
}); });
} }
void customDiskIOThread::async_delete_files(lt::storage_index_t storage, lt::remove_flags_t options void CustomDiskIOThread::async_delete_files(lt::storage_index_t storage, lt::remove_flags_t options
, std::function<void (const lt::storage_error &)> handler) , std::function<void (const lt::storage_error &)> handler)
{ {
m_nativeDiskIO->async_delete_files(storage, options, std::move(handler)); m_nativeDiskIO->async_delete_files(storage, options, std::move(handler));
} }
void customDiskIOThread::async_set_file_priority(lt::storage_index_t storage, lt::aux::vector<lt::download_priority_t, lt::file_index_t> priorities void CustomDiskIOThread::async_set_file_priority(lt::storage_index_t storage, lt::aux::vector<lt::download_priority_t, lt::file_index_t> priorities
, std::function<void (const lt::storage_error &, lt::aux::vector<lt::download_priority_t, lt::file_index_t>)> handler) , std::function<void (const lt::storage_error &, lt::aux::vector<lt::download_priority_t, lt::file_index_t>)> handler)
{ {
m_nativeDiskIO->async_set_file_priority(storage, priorities m_nativeDiskIO->async_set_file_priority(storage, priorities
@@ -160,43 +161,44 @@ void customDiskIOThread::async_set_file_priority(lt::storage_index_t storage, lt
}); });
} }
void customDiskIOThread::async_clear_piece(lt::storage_index_t storage, lt::piece_index_t index void CustomDiskIOThread::async_clear_piece(lt::storage_index_t storage, lt::piece_index_t index
, std::function<void (lt::piece_index_t)> handler) , std::function<void (lt::piece_index_t)> handler)
{ {
m_nativeDiskIO->async_clear_piece(storage, index, std::move(handler)); m_nativeDiskIO->async_clear_piece(storage, index, std::move(handler));
} }
void customDiskIOThread::update_stats_counters(lt::counters &counters) const void CustomDiskIOThread::update_stats_counters(lt::counters &counters) const
{ {
m_nativeDiskIO->update_stats_counters(counters); m_nativeDiskIO->update_stats_counters(counters);
} }
std::vector<lt::open_file_state> customDiskIOThread::get_status(lt::storage_index_t index) const std::vector<lt::open_file_state> CustomDiskIOThread::get_status(lt::storage_index_t index) const
{ {
return m_nativeDiskIO->get_status(index); return m_nativeDiskIO->get_status(index);
} }
void customDiskIOThread::abort(bool wait) void CustomDiskIOThread::abort(bool wait)
{ {
m_nativeDiskIO->abort(wait); m_nativeDiskIO->abort(wait);
} }
void customDiskIOThread::submit_jobs() void CustomDiskIOThread::submit_jobs()
{ {
m_nativeDiskIO->submit_jobs(); m_nativeDiskIO->submit_jobs();
} }
void customDiskIOThread::settings_updated() void CustomDiskIOThread::settings_updated()
{ {
m_nativeDiskIO->settings_updated(); m_nativeDiskIO->settings_updated();
} }
void customDiskIOThread::handleCompleteFiles(lt::storage_index_t storage, const QString &savePath) void CustomDiskIOThread::handleCompleteFiles(lt::storage_index_t storage, const QString &savePath)
{ {
const QDir saveDir {savePath}; const QDir saveDir {savePath};
const StorageData storageData = m_storageData[storage]; const StorageData storageData = m_storageData[storage];
const lt::file_storage &fileStorage = storageData.files; const lt::file_storage &fileStorage = storageData.files;
for (const lt::file_index_t fileIndex : fileStorage.file_range()) { for (const lt::file_index_t fileIndex : fileStorage.file_range())
{
// ignore files that have priority 0 // ignore files that have priority 0
if ((storageData.filePriorities.end_index() > fileIndex) && (storageData.filePriorities[fileIndex] == lt::dont_download)) if ((storageData.filePriorities.end_index() > fileIndex) && (storageData.filePriorities[fileIndex] == lt::dont_download))
continue; continue;
@@ -205,10 +207,12 @@ void customDiskIOThread::handleCompleteFiles(lt::storage_index_t storage, const
if (fileStorage.pad_file_at(fileIndex)) continue; if (fileStorage.pad_file_at(fileIndex)) continue;
const QString filePath = QString::fromStdString(fileStorage.file_path(fileIndex)); const QString filePath = QString::fromStdString(fileStorage.file_path(fileIndex));
if (filePath.endsWith(QB_EXT)) { if (filePath.endsWith(QB_EXT))
{
const QString completeFilePath = filePath.left(filePath.size() - QB_EXT.size()); const QString completeFilePath = filePath.left(filePath.size() - QB_EXT.size());
QFile completeFile {saveDir.absoluteFilePath(completeFilePath)}; QFile completeFile {saveDir.absoluteFilePath(completeFilePath)};
if (completeFile.exists()) { if (completeFile.exists())
{
QFile incompleteFile {saveDir.absoluteFilePath(filePath)}; QFile incompleteFile {saveDir.absoluteFilePath(filePath)};
incompleteFile.remove(); incompleteFile.remove();
completeFile.rename(incompleteFile.fileName()); completeFile.rename(incompleteFile.fileName());
@@ -261,7 +265,8 @@ void CustomStorage::handleCompleteFiles(const QString &savePath)
const QDir saveDir {savePath}; const QDir saveDir {savePath};
const lt::file_storage &fileStorage = files(); const lt::file_storage &fileStorage = files();
for (const lt::file_index_t fileIndex : fileStorage.file_range()) { for (const lt::file_index_t fileIndex : fileStorage.file_range())
{
// ignore files that have priority 0 // ignore files that have priority 0
if ((m_filePriorities.end_index() > fileIndex) && (m_filePriorities[fileIndex] == lt::dont_download)) if ((m_filePriorities.end_index() > fileIndex) && (m_filePriorities[fileIndex] == lt::dont_download))
continue; continue;
@@ -270,13 +275,14 @@ void CustomStorage::handleCompleteFiles(const QString &savePath)
if (fileStorage.pad_file_at(fileIndex)) continue; if (fileStorage.pad_file_at(fileIndex)) continue;
const QString filePath = QString::fromStdString(fileStorage.file_path(fileIndex)); const QString filePath = QString::fromStdString(fileStorage.file_path(fileIndex));
if (filePath.endsWith(QB_EXT)) { if (filePath.endsWith(QB_EXT))
{
const QString completeFilePath = filePath.left(filePath.size() - QB_EXT.size()); const QString completeFilePath = filePath.left(filePath.size() - QB_EXT.size());
QFile completeFile {saveDir.absoluteFilePath(completeFilePath)}; QFile completeFile {saveDir.absoluteFilePath(completeFilePath)};
if (completeFile.exists()) { if (completeFile.exists())
{
QFile incompleteFile {saveDir.absoluteFilePath(filePath)}; QFile incompleteFile {saveDir.absoluteFilePath(filePath)};
if (incompleteFile.exists()) incompleteFile.remove();
incompleteFile.remove();
completeFile.rename(incompleteFile.fileName()); completeFile.rename(incompleteFile.fileName());
} }
} }

View File

@@ -40,6 +40,8 @@
#include <libtorrent/io_context.hpp> #include <libtorrent/io_context.hpp>
#include <QHash> #include <QHash>
#include "ltqhash.h"
#else #else
#include <libtorrent/storage.hpp> #include <libtorrent/storage.hpp>
#endif #endif
@@ -48,10 +50,10 @@
std::unique_ptr<lt::disk_interface> customDiskIOConstructor( std::unique_ptr<lt::disk_interface> customDiskIOConstructor(
lt::io_context &ioContext, lt::settings_interface const &settings, lt::counters &counters); lt::io_context &ioContext, lt::settings_interface const &settings, lt::counters &counters);
class customDiskIOThread final : public lt::disk_interface class CustomDiskIOThread final : public lt::disk_interface
{ {
public: public:
explicit customDiskIOThread(std::unique_ptr<libtorrent::disk_interface> nativeDiskIOThread); explicit CustomDiskIOThread(std::unique_ptr<libtorrent::disk_interface> nativeDiskIOThread);
lt::storage_holder new_torrent(const lt::storage_params &storageParams, const std::shared_ptr<void> &torrent) override; lt::storage_holder new_torrent(const lt::storage_params &storageParams, const std::shared_ptr<void> &torrent) override;
void remove_torrent(lt::storage_index_t storageIndex) override; void remove_torrent(lt::storage_index_t storageIndex) override;

View File

@@ -32,7 +32,8 @@ namespace BitTorrent
{ {
bool isValidDownloadPriority(const DownloadPriority priority) bool isValidDownloadPriority(const DownloadPriority priority)
{ {
switch (priority) { switch (priority)
{
case DownloadPriority::Ignored: case DownloadPriority::Ignored:
case DownloadPriority::Normal: case DownloadPriority::Normal:
case DownloadPriority::High: case DownloadPriority::High:

View File

@@ -48,8 +48,10 @@ namespace
const char *octetStart = str; const char *octetStart = str;
char *endptr; char *endptr;
for (; *str; ++str) { for (; *str; ++str)
if (*str == '.') { {
if (*str == '.')
{
const long int extractedNum = strtol(octetStart, &endptr, 10); const long int extractedNum = strtol(octetStart, &endptr, 10);
if ((extractedNum >= 0L) && (extractedNum <= 255L)) if ((extractedNum >= 0L) && (extractedNum <= 255L))
m_buf[octetIndex++] = static_cast<unsigned char>(extractedNum); m_buf[octetIndex++] = static_cast<unsigned char>(extractedNum);
@@ -65,7 +67,8 @@ namespace
} }
} }
if (str != octetStart) { if (str != octetStart)
{
const long int extractedNum = strtol(octetStart, &endptr, 10); const long int extractedNum = strtol(octetStart, &endptr, 10);
if ((extractedNum >= 0L) && (extractedNum <= 255L)) if ((extractedNum >= 0L) && (extractedNum <= 255L))
m_buf[octetIndex] = static_cast<unsigned char>(strtol(octetStart, &endptr, 10)); m_buf[octetIndex] = static_cast<unsigned char>(strtol(octetStart, &endptr, 10));
@@ -124,7 +127,8 @@ int FilterParserThread::parseDATFilterFile()
QFile file(m_filePath); QFile file(m_filePath);
if (!file.exists()) return ruleCount; if (!file.exists()) return ruleCount;
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
LogMsg(tr("I/O Error: Could not open IP filter file in read mode."), Log::CRITICAL); LogMsg(tr("I/O Error: Could not open IP filter file in read mode."), Log::CRITICAL);
return ruleCount; return ruleCount;
} }
@@ -142,7 +146,8 @@ int FilterParserThread::parseDATFilterFile()
LogMsg(msg, Log::CRITICAL); LogMsg(msg, Log::CRITICAL);
}; };
while (true) { while (true)
{
bytesRead = file.read(buffer.data() + offset, BUFFER_SIZE - offset - 1); bytesRead = file.read(buffer.data() + offset, BUFFER_SIZE - offset - 1);
if (bytesRead < 0) if (bytesRead < 0)
break; break;
@@ -150,12 +155,16 @@ int FilterParserThread::parseDATFilterFile()
if ((bytesRead == 0) && (dataSize == 0)) if ((bytesRead == 0) && (dataSize == 0))
break; break;
for (start = 0; start < dataSize; ++start) { for (start = 0; start < dataSize; ++start)
{
endOfLine = -1; endOfLine = -1;
// The file might have ended without the last line having a newline // The file might have ended without the last line having a newline
if (!((bytesRead == 0) && (dataSize > 0))) { if (!((bytesRead == 0) && (dataSize > 0)))
for (int i = start; i < dataSize; ++i) { {
if (buffer[i] == '\n') { for (int i = start; i < dataSize; ++i)
{
if (buffer[i] == '\n')
{
endOfLine = i; endOfLine = i;
// We need to NULL the newline in case the line has only an IP range. // We need to NULL the newline in case the line has only an IP range.
// In that case the parser won't work for the end IP, because it ends // In that case the parser won't work for the end IP, because it ends
@@ -165,12 +174,14 @@ int FilterParserThread::parseDATFilterFile()
} }
} }
} }
else { else
{
endOfLine = dataSize; endOfLine = dataSize;
buffer[dataSize] = '\0'; buffer[dataSize] = '\0';
} }
if (endOfLine == -1) { if (endOfLine == -1)
{
// read the next chunk from file // read the next chunk from file
// but first move(copy) the leftover data to the front of the buffer // but first move(copy) the leftover data to the front of the buffer
offset = dataSize - start; offset = dataSize - start;
@@ -181,7 +192,8 @@ int FilterParserThread::parseDATFilterFile()
++nbLine; ++nbLine;
if ((buffer[start] == '#') if ((buffer[start] == '#')
|| ((buffer[start] == '/') && ((start + 1 < dataSize) && (buffer[start + 1] == '/')))) { || ((buffer[start] == '/') && ((start + 1 < dataSize) && (buffer[start + 1] == '/'))))
{
start = endOfLine; start = endOfLine;
continue; continue;
} }
@@ -194,11 +206,13 @@ int FilterParserThread::parseDATFilterFile()
findAndNullDelimiter(buffer.data(), ',', firstComma + 1, endOfLine); findAndNullDelimiter(buffer.data(), ',', firstComma + 1, endOfLine);
// Check if there is an access value (apparently not mandatory) // Check if there is an access value (apparently not mandatory)
if (firstComma != -1) { if (firstComma != -1)
{
// There is possibly one // There is possibly one
const long int nbAccess = strtol(buffer.data() + firstComma + 1, nullptr, 10); const long int nbAccess = strtol(buffer.data() + firstComma + 1, nullptr, 10);
// Ignoring this rule because access value is too high // Ignoring this rule because access value is too high
if (nbAccess > 127L) { if (nbAccess > 127L)
{
start = endOfLine; start = endOfLine;
continue; continue;
} }
@@ -207,7 +221,8 @@ int FilterParserThread::parseDATFilterFile()
// IP Range should be split by a dash // IP Range should be split by a dash
const int endOfIPRange = ((firstComma == -1) ? (endOfLine - 1) : (firstComma - 1)); const int endOfIPRange = ((firstComma == -1) ? (endOfLine - 1) : (firstComma - 1));
const int delimIP = findAndNullDelimiter(buffer.data(), '-', start, endOfIPRange); const int delimIP = findAndNullDelimiter(buffer.data(), '-', start, endOfIPRange);
if (delimIP == -1) { if (delimIP == -1)
{
++parseErrorCount; ++parseErrorCount;
addLog(tr("IP filter line %1 is malformed.").arg(nbLine)); addLog(tr("IP filter line %1 is malformed.").arg(nbLine));
start = endOfLine; start = endOfLine;
@@ -216,7 +231,8 @@ int FilterParserThread::parseDATFilterFile()
lt::address startAddr; lt::address startAddr;
int newStart = trim(buffer.data(), start, delimIP - 1); int newStart = trim(buffer.data(), start, delimIP - 1);
if (!parseIPAddress(buffer.data() + newStart, startAddr)) { if (!parseIPAddress(buffer.data() + newStart, startAddr))
{
++parseErrorCount; ++parseErrorCount;
addLog(tr("IP filter line %1 is malformed. Start IP of the range is malformed.").arg(nbLine)); addLog(tr("IP filter line %1 is malformed. Start IP of the range is malformed.").arg(nbLine));
start = endOfLine; start = endOfLine;
@@ -225,7 +241,8 @@ int FilterParserThread::parseDATFilterFile()
lt::address endAddr; lt::address endAddr;
newStart = trim(buffer.data(), delimIP + 1, endOfIPRange); newStart = trim(buffer.data(), delimIP + 1, endOfIPRange);
if (!parseIPAddress(buffer.data() + newStart, endAddr)) { if (!parseIPAddress(buffer.data() + newStart, endAddr))
{
++parseErrorCount; ++parseErrorCount;
addLog(tr("IP filter line %1 is malformed. End IP of the range is malformed.").arg(nbLine)); addLog(tr("IP filter line %1 is malformed. End IP of the range is malformed.").arg(nbLine));
start = endOfLine; start = endOfLine;
@@ -233,7 +250,8 @@ int FilterParserThread::parseDATFilterFile()
} }
if ((startAddr.is_v4() != endAddr.is_v4()) if ((startAddr.is_v4() != endAddr.is_v4())
|| (startAddr.is_v6() != endAddr.is_v6())) { || (startAddr.is_v6() != endAddr.is_v6()))
{
++parseErrorCount; ++parseErrorCount;
addLog(tr("IP filter line %1 is malformed. One IP is IPv4 and the other is IPv6!").arg(nbLine)); addLog(tr("IP filter line %1 is malformed. One IP is IPv4 and the other is IPv6!").arg(nbLine));
start = endOfLine; start = endOfLine;
@@ -243,11 +261,13 @@ int FilterParserThread::parseDATFilterFile()
start = endOfLine; start = endOfLine;
// Now Add to the filter // Now Add to the filter
try { try
{
m_filter.add_rule(startAddr, endAddr, lt::ip_filter::blocked); m_filter.add_rule(startAddr, endAddr, lt::ip_filter::blocked);
++ruleCount; ++ruleCount;
} }
catch (const std::exception &e) { catch (const std::exception &e)
{
++parseErrorCount; ++parseErrorCount;
addLog(tr("IP filter exception thrown for line %1. Exception is: %2") addLog(tr("IP filter exception thrown for line %1. Exception is: %2")
.arg(nbLine).arg(QString::fromLocal8Bit(e.what()))); .arg(nbLine).arg(QString::fromLocal8Bit(e.what())));
@@ -271,7 +291,8 @@ int FilterParserThread::parseP2PFilterFile()
QFile file(m_filePath); QFile file(m_filePath);
if (!file.exists()) return ruleCount; if (!file.exists()) return ruleCount;
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
LogMsg(tr("I/O Error: Could not open IP filter file in read mode."), Log::CRITICAL); LogMsg(tr("I/O Error: Could not open IP filter file in read mode."), Log::CRITICAL);
return ruleCount; return ruleCount;
} }
@@ -289,7 +310,8 @@ int FilterParserThread::parseP2PFilterFile()
LogMsg(msg, Log::CRITICAL); LogMsg(msg, Log::CRITICAL);
}; };
while (true) { while (true)
{
bytesRead = file.read(buffer.data() + offset, BUFFER_SIZE - offset - 1); bytesRead = file.read(buffer.data() + offset, BUFFER_SIZE - offset - 1);
if (bytesRead < 0) if (bytesRead < 0)
break; break;
@@ -297,12 +319,16 @@ int FilterParserThread::parseP2PFilterFile()
if ((bytesRead == 0) && (dataSize == 0)) if ((bytesRead == 0) && (dataSize == 0))
break; break;
for (start = 0; start < dataSize; ++start) { for (start = 0; start < dataSize; ++start)
{
endOfLine = -1; endOfLine = -1;
// The file might have ended without the last line having a newline // The file might have ended without the last line having a newline
if (!((bytesRead == 0) && (dataSize > 0))) { if (!((bytesRead == 0) && (dataSize > 0)))
for (int i = start; i < dataSize; ++i) { {
if (buffer[i] == '\n') { for (int i = start; i < dataSize; ++i)
{
if (buffer[i] == '\n')
{
endOfLine = i; endOfLine = i;
// We need to NULL the newline in case the line has only an IP range. // We need to NULL the newline in case the line has only an IP range.
// In that case the parser won't work for the end IP, because it ends // In that case the parser won't work for the end IP, because it ends
@@ -312,12 +338,14 @@ int FilterParserThread::parseP2PFilterFile()
} }
} }
} }
else { else
{
endOfLine = dataSize; endOfLine = dataSize;
buffer[dataSize] = '\0'; buffer[dataSize] = '\0';
} }
if (endOfLine == -1) { if (endOfLine == -1)
{
// read the next chunk from file // read the next chunk from file
// but first move(copy) the leftover data to the front of the buffer // but first move(copy) the leftover data to the front of the buffer
offset = dataSize - start; offset = dataSize - start;
@@ -328,7 +356,8 @@ int FilterParserThread::parseP2PFilterFile()
++nbLine; ++nbLine;
if ((buffer[start] == '#') if ((buffer[start] == '#')
|| ((buffer[start] == '/') && ((start + 1 < dataSize) && (buffer[start + 1] == '/')))) { || ((buffer[start] == '/') && ((start + 1 < dataSize) && (buffer[start + 1] == '/'))))
{
start = endOfLine; start = endOfLine;
continue; continue;
} }
@@ -337,7 +366,8 @@ int FilterParserThread::parseP2PFilterFile()
// Some organization:1.0.0.0-1.255.255.255 // Some organization:1.0.0.0-1.255.255.255
// The "Some organization" part might contain a ':' char itself so we find the last occurrence // The "Some organization" part might contain a ':' char itself so we find the last occurrence
const int partsDelimiter = findAndNullDelimiter(buffer.data(), ':', start, endOfLine, true); const int partsDelimiter = findAndNullDelimiter(buffer.data(), ':', start, endOfLine, true);
if (partsDelimiter == -1) { if (partsDelimiter == -1)
{
++parseErrorCount; ++parseErrorCount;
addLog(tr("IP filter line %1 is malformed.").arg(nbLine)); addLog(tr("IP filter line %1 is malformed.").arg(nbLine));
start = endOfLine; start = endOfLine;
@@ -346,7 +376,8 @@ int FilterParserThread::parseP2PFilterFile()
// IP Range should be split by a dash // IP Range should be split by a dash
const int delimIP = findAndNullDelimiter(buffer.data(), '-', partsDelimiter + 1, endOfLine); const int delimIP = findAndNullDelimiter(buffer.data(), '-', partsDelimiter + 1, endOfLine);
if (delimIP == -1) { if (delimIP == -1)
{
++parseErrorCount; ++parseErrorCount;
addLog(tr("IP filter line %1 is malformed.").arg(nbLine)); addLog(tr("IP filter line %1 is malformed.").arg(nbLine));
start = endOfLine; start = endOfLine;
@@ -355,7 +386,8 @@ int FilterParserThread::parseP2PFilterFile()
lt::address startAddr; lt::address startAddr;
int newStart = trim(buffer.data(), partsDelimiter + 1, delimIP - 1); int newStart = trim(buffer.data(), partsDelimiter + 1, delimIP - 1);
if (!parseIPAddress(buffer.data() + newStart, startAddr)) { if (!parseIPAddress(buffer.data() + newStart, startAddr))
{
++parseErrorCount; ++parseErrorCount;
addLog(tr("IP filter line %1 is malformed. Start IP of the range is malformed.").arg(nbLine)); addLog(tr("IP filter line %1 is malformed. Start IP of the range is malformed.").arg(nbLine));
start = endOfLine; start = endOfLine;
@@ -364,7 +396,8 @@ int FilterParserThread::parseP2PFilterFile()
lt::address endAddr; lt::address endAddr;
newStart = trim(buffer.data(), delimIP + 1, endOfLine); newStart = trim(buffer.data(), delimIP + 1, endOfLine);
if (!parseIPAddress(buffer.data() + newStart, endAddr)) { if (!parseIPAddress(buffer.data() + newStart, endAddr))
{
++parseErrorCount; ++parseErrorCount;
addLog(tr("IP filter line %1 is malformed. End IP of the range is malformed.").arg(nbLine)); addLog(tr("IP filter line %1 is malformed. End IP of the range is malformed.").arg(nbLine));
start = endOfLine; start = endOfLine;
@@ -372,7 +405,8 @@ int FilterParserThread::parseP2PFilterFile()
} }
if ((startAddr.is_v4() != endAddr.is_v4()) if ((startAddr.is_v4() != endAddr.is_v4())
|| (startAddr.is_v6() != endAddr.is_v6())) { || (startAddr.is_v6() != endAddr.is_v6()))
{
++parseErrorCount; ++parseErrorCount;
addLog(tr("IP filter line %1 is malformed. One IP is IPv4 and the other is IPv6!").arg(nbLine)); addLog(tr("IP filter line %1 is malformed. One IP is IPv4 and the other is IPv6!").arg(nbLine));
start = endOfLine; start = endOfLine;
@@ -381,11 +415,13 @@ int FilterParserThread::parseP2PFilterFile()
start = endOfLine; start = endOfLine;
try { try
{
m_filter.add_rule(startAddr, endAddr, lt::ip_filter::blocked); m_filter.add_rule(startAddr, endAddr, lt::ip_filter::blocked);
++ruleCount; ++ruleCount;
} }
catch (const std::exception &e) { catch (const std::exception &e)
{
++parseErrorCount; ++parseErrorCount;
addLog(tr("IP filter exception thrown for line %1. Exception is: %2") addLog(tr("IP filter exception thrown for line %1. Exception is: %2")
.arg(nbLine).arg(QString::fromLocal8Bit(e.what()))); .arg(nbLine).arg(QString::fromLocal8Bit(e.what())));
@@ -407,14 +443,18 @@ int FilterParserThread::getlineInStream(QDataStream &stream, std::string &name,
char c; char c;
int totalRead = 0; int totalRead = 0;
int read; int read;
do { do
{
read = stream.readRawData(&c, 1); read = stream.readRawData(&c, 1);
totalRead += read; totalRead += read;
if (read > 0) { if (read > 0)
if (c != delim) { {
if (c != delim)
{
name += c; name += c;
} }
else { else
{
// Delim found // Delim found
return totalRead; return totalRead;
} }
@@ -432,7 +472,8 @@ int FilterParserThread::parseP2BFilterFile()
QFile file(m_filePath); QFile file(m_filePath);
if (!file.exists()) return ruleCount; if (!file.exists()) return ruleCount;
if (!file.open(QIODevice::ReadOnly)) { if (!file.open(QIODevice::ReadOnly))
{
LogMsg(tr("I/O Error: Could not open IP filter file in read mode."), Log::CRITICAL); LogMsg(tr("I/O Error: Could not open IP filter file in read mode."), Log::CRITICAL);
return ruleCount; return ruleCount;
} }
@@ -443,19 +484,23 @@ int FilterParserThread::parseP2BFilterFile()
unsigned char version; unsigned char version;
if (!stream.readRawData(buf, sizeof(buf)) if (!stream.readRawData(buf, sizeof(buf))
|| memcmp(buf, "\xFF\xFF\xFF\xFFP2B", 7) || memcmp(buf, "\xFF\xFF\xFF\xFFP2B", 7)
|| !stream.readRawData(reinterpret_cast<char*>(&version), sizeof(version))) { || !stream.readRawData(reinterpret_cast<char*>(&version), sizeof(version)))
{
LogMsg(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL); LogMsg(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
return ruleCount; return ruleCount;
} }
if ((version == 1) || (version == 2)) { if ((version == 1) || (version == 2))
{
qDebug ("p2b version 1 or 2"); qDebug ("p2b version 1 or 2");
unsigned int start, end; unsigned int start, end;
std::string name; std::string name;
while (getlineInStream(stream, name, '\0') && !m_abort) { while (getlineInStream(stream, name, '\0') && !m_abort)
{
if (!stream.readRawData(reinterpret_cast<char*>(&start), sizeof(start)) if (!stream.readRawData(reinterpret_cast<char*>(&start), sizeof(start))
|| !stream.readRawData(reinterpret_cast<char*>(&end), sizeof(end))) { || !stream.readRawData(reinterpret_cast<char*>(&end), sizeof(end)))
{
LogMsg(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL); LogMsg(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
return ruleCount; return ruleCount;
} }
@@ -466,26 +511,31 @@ int FilterParserThread::parseP2BFilterFile()
const lt::address_v4 first(ntohl(start)); const lt::address_v4 first(ntohl(start));
const lt::address_v4 last(ntohl(end)); const lt::address_v4 last(ntohl(end));
// Apply to bittorrent session // Apply to bittorrent session
try { try
{
m_filter.add_rule(first, last, lt::ip_filter::blocked); m_filter.add_rule(first, last, lt::ip_filter::blocked);
++ruleCount; ++ruleCount;
} }
catch (const std::exception &) {} catch (const std::exception &) {}
} }
} }
else if (version == 3) { else if (version == 3)
{
qDebug ("p2b version 3"); qDebug ("p2b version 3");
unsigned int namecount; unsigned int namecount;
if (!stream.readRawData(reinterpret_cast<char*>(&namecount), sizeof(namecount))) { if (!stream.readRawData(reinterpret_cast<char*>(&namecount), sizeof(namecount)))
{
LogMsg(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL); LogMsg(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
return ruleCount; return ruleCount;
} }
namecount = ntohl(namecount); namecount = ntohl(namecount);
// Reading names although, we don't really care about them // Reading names although, we don't really care about them
for (unsigned int i = 0; i < namecount; ++i) { for (unsigned int i = 0; i < namecount; ++i)
{
std::string name; std::string name;
if (!getlineInStream(stream, name, '\0')) { if (!getlineInStream(stream, name, '\0'))
{
LogMsg(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL); LogMsg(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
return ruleCount; return ruleCount;
} }
@@ -495,17 +545,20 @@ int FilterParserThread::parseP2BFilterFile()
// Reading the ranges // Reading the ranges
unsigned int rangecount; unsigned int rangecount;
if (!stream.readRawData(reinterpret_cast<char*>(&rangecount), sizeof(rangecount))) { if (!stream.readRawData(reinterpret_cast<char*>(&rangecount), sizeof(rangecount)))
{
LogMsg(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL); LogMsg(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
return ruleCount; return ruleCount;
} }
rangecount = ntohl(rangecount); rangecount = ntohl(rangecount);
unsigned int name, start, end; unsigned int name, start, end;
for (unsigned int i = 0; i < rangecount; ++i) { for (unsigned int i = 0; i < rangecount; ++i)
{
if (!stream.readRawData(reinterpret_cast<char*>(&name), sizeof(name)) if (!stream.readRawData(reinterpret_cast<char*>(&name), sizeof(name))
|| !stream.readRawData(reinterpret_cast<char*>(&start), sizeof(start)) || !stream.readRawData(reinterpret_cast<char*>(&start), sizeof(start))
|| !stream.readRawData(reinterpret_cast<char*>(&end), sizeof(end))) { || !stream.readRawData(reinterpret_cast<char*>(&end), sizeof(end)))
{
LogMsg(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL); LogMsg(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
return ruleCount; return ruleCount;
} }
@@ -516,7 +569,8 @@ int FilterParserThread::parseP2BFilterFile()
const lt::address_v4 first(ntohl(start)); const lt::address_v4 first(ntohl(start));
const lt::address_v4 last(ntohl(end)); const lt::address_v4 last(ntohl(end));
// Apply to bittorrent session // Apply to bittorrent session
try { try
{
m_filter.add_rule(first, last, lt::ip_filter::blocked); m_filter.add_rule(first, last, lt::ip_filter::blocked);
++ruleCount; ++ruleCount;
} }
@@ -525,7 +579,8 @@ int FilterParserThread::parseP2BFilterFile()
if (m_abort) return ruleCount; if (m_abort) return ruleCount;
} }
} }
else { else
{
LogMsg(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL); LogMsg(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
} }
@@ -539,7 +594,8 @@ int FilterParserThread::parseP2BFilterFile()
// * PeerGuardian Binary (P2B): http://wiki.phoenixlabs.org/wiki/P2B_Format // * PeerGuardian Binary (P2B): http://wiki.phoenixlabs.org/wiki/P2B_Format
void FilterParserThread::processFilterFile(const QString &filePath) void FilterParserThread::processFilterFile(const QString &filePath)
{ {
if (isRunning()) { if (isRunning())
{
// Already parsing a filter, m_abort first // Already parsing a filter, m_abort first
m_abort = true; m_abort = true;
wait(); wait();
@@ -561,25 +617,30 @@ void FilterParserThread::run()
{ {
qDebug("Processing filter file"); qDebug("Processing filter file");
int ruleCount = 0; int ruleCount = 0;
if (m_filePath.endsWith(".p2p", Qt::CaseInsensitive)) { if (m_filePath.endsWith(".p2p", Qt::CaseInsensitive))
{
// PeerGuardian p2p file // PeerGuardian p2p file
ruleCount = parseP2PFilterFile(); ruleCount = parseP2PFilterFile();
} }
else if (m_filePath.endsWith(".p2b", Qt::CaseInsensitive)) { else if (m_filePath.endsWith(".p2b", Qt::CaseInsensitive))
{
// PeerGuardian p2b file // PeerGuardian p2b file
ruleCount = parseP2BFilterFile(); ruleCount = parseP2BFilterFile();
} }
else if (m_filePath.endsWith(".dat", Qt::CaseInsensitive)) { else if (m_filePath.endsWith(".dat", Qt::CaseInsensitive))
{
// eMule DAT format // eMule DAT format
ruleCount = parseDATFilterFile(); ruleCount = parseDATFilterFile();
} }
if (m_abort) return; if (m_abort) return;
try { try
{
emit IPFilterParsed(ruleCount); emit IPFilterParsed(ruleCount);
} }
catch (const std::exception &) { catch (const std::exception &)
{
emit IPFilterError(); emit IPFilterError();
} }
@@ -588,17 +649,23 @@ void FilterParserThread::run()
int FilterParserThread::findAndNullDelimiter(char *const data, const char delimiter, const int start, const int end, const bool reverse) int FilterParserThread::findAndNullDelimiter(char *const data, const char delimiter, const int start, const int end, const bool reverse)
{ {
if (!reverse) { if (!reverse)
for (int i = start; i <= end; ++i) { {
if (data[i] == delimiter) { for (int i = start; i <= end; ++i)
{
if (data[i] == delimiter)
{
data[i] = '\0'; data[i] = '\0';
return i; return i;
} }
} }
} }
else { else
for (int i = end; i >= start; --i) { {
if (data[i] == delimiter) { for (int i = end; i >= start; --i)
{
if (data[i] == delimiter)
{
data[i] = '\0'; data[i] = '\0';
return i; return i;
} }
@@ -613,17 +680,21 @@ int FilterParserThread::trim(char *const data, const int start, const int end)
if (start >= end) return start; if (start >= end) return start;
int newStart = start; int newStart = start;
for (int i = start; i <= end; ++i) { for (int i = start; i <= end; ++i)
if (isspace(data[i]) != 0) { {
if (isspace(data[i]) != 0)
{
data[i] = '\0'; data[i] = '\0';
} }
else { else
{
newStart = i; newStart = i;
break; break;
} }
} }
for (int i = end; i >= start; --i) { for (int i = end; i >= start; --i)
{
if (isspace(data[i]) != 0) if (isspace(data[i]) != 0)
data[i] = '\0'; data[i] = '\0';
else else

View File

@@ -0,0 +1,47 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2020 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#pragma once
#include <functional>
#include <libtorrent/units.hpp>
#include <QHash>
namespace libtorrent
{
namespace aux
{
template <typename T, typename Tag>
uint qHash(const strong_typedef<T, Tag> &key, const uint seed)
{
return ::qHash((std::hash<strong_typedef<T, Tag>> {})(key), seed);
}
}
}

View File

@@ -42,7 +42,7 @@ namespace
{ {
bool isBitTorrentInfoHash(const QString &string) bool isBitTorrentInfoHash(const QString &string)
{ {
// There are 2 represenations for BitTorrent info hash: // There are 2 representations for BitTorrent info hash:
// 1. 40 chars hex-encoded string // 1. 40 chars hex-encoded string
// == 20 (SHA-1 length in bytes) * 2 (each byte maps to 2 hex characters) // == 20 (SHA-1 length in bytes) * 2 (each byte maps to 2 hex characters)
// 2. 32 chars Base32 encoded string // 2. 32 chars Base32 encoded string

View File

@@ -36,7 +36,8 @@ namespace
{ {
void handleFastresumeRejectedAlert(const lt::fastresume_rejected_alert *alert) void handleFastresumeRejectedAlert(const lt::fastresume_rejected_alert *alert)
{ {
if (alert->error.value() == lt::errors::mismatching_file_size) { if (alert->error.value() == lt::errors::mismatching_file_size)
{
alert->handle.unset_flags(lt::torrent_flags::auto_managed); alert->handle.unset_flags(lt::torrent_flags::auto_managed);
alert->handle.pause(); alert->handle.pause();
} }
@@ -55,7 +56,8 @@ std::shared_ptr<lt::torrent_plugin> NativeSessionExtension::new_torrent(const lt
void NativeSessionExtension::on_alert(const lt::alert *alert) void NativeSessionExtension::on_alert(const lt::alert *alert)
{ {
switch (alert->type()) { switch (alert->type())
{
case lt::fastresume_rejected_alert::alert_type: case lt::fastresume_rejected_alert::alert_type:
handleFastresumeRejectedAlert(static_cast<const lt::fastresume_rejected_alert *>(alert)); handleFastresumeRejectedAlert(static_cast<const lt::fastresume_rejected_alert *>(alert));
break; break;

View File

@@ -32,12 +32,6 @@
namespace namespace
{ {
bool isPaused(const lt::torrent_status &torrentStatus)
{
return ((torrentStatus.flags & lt::torrent_flags::paused)
&& !(torrentStatus.flags & lt::torrent_flags::auto_managed));
}
bool isAutoManaged(const lt::torrent_status &torrentStatus) bool isAutoManaged(const lt::torrent_status &torrentStatus)
{ {
return static_cast<bool>(torrentStatus.flags & lt::torrent_flags::auto_managed); return static_cast<bool>(torrentStatus.flags & lt::torrent_flags::auto_managed);
@@ -49,17 +43,6 @@ NativeTorrentExtension::NativeTorrentExtension(const lt::torrent_handle &torrent
{ {
} }
// This method is called when state of torrent is changed
void NativeTorrentExtension::on_state(const lt::torrent_status::state_t state)
{
// When a torrent enters "checking files" state while paused, we temporarily resume it
// (really we just allow libtorrent to resume it by enabling auto management for it).
if (state == lt::torrent_status::checking_files) {
if (isPaused(m_torrentHandle.status({})))
m_torrentHandle.set_flags(lt::torrent_flags::stop_when_ready | lt::torrent_flags::auto_managed);
}
}
bool NativeTorrentExtension::on_pause() bool NativeTorrentExtension::on_pause()
{ {
if (!isAutoManaged(m_torrentHandle.status({}))) if (!isAutoManaged(m_torrentHandle.status({})))

View File

@@ -37,7 +37,6 @@ public:
explicit NativeTorrentExtension(const lt::torrent_handle &torrentHandle); explicit NativeTorrentExtension(const lt::torrent_handle &torrentHandle);
private: private:
void on_state(lt::torrent_status::state_t state) override;
bool on_pause() override; bool on_pause() override;
lt::torrent_handle m_torrentHandle; lt::torrent_handle m_torrentHandle;

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