Improve coding style

This commit is contained in:
Vladimir Golovnev (Glassez)
2020-11-16 10:02:11 +03:00
parent acad35c5bc
commit c41df9ffbd
147 changed files with 4454 additions and 2227 deletions

View File

@@ -38,7 +38,8 @@ AsyncFileStorage::AsyncFileStorage(const QString &storageFolderPath, QObject *pa
, m_lockFile(m_storageDir.absoluteFilePath(QStringLiteral("storage.lock")))
{
if (!m_storageDir.mkpath(m_storageDir.absolutePath()))
throw AsyncFileStorageError {tr("Could not create directory '%1'.")
throw AsyncFileStorageError
{tr("Could not create directory '%1'.")
.arg(m_storageDir.absolutePath())};
// 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);
QSaveFile file(filePath);
qDebug() << "AsyncFileStorage: Saving data to" << filePath;
if (file.open(QIODevice::WriteOnly)) {
if (file.open(QIODevice::WriteOnly))
{
file.write(data);
if (!file.commit()) {
if (!file.commit())
{
qDebug() << "AsyncFileStorage: Failed to save data";
emit failed(filePath, file.errorString());
}

View File

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

View File

@@ -54,7 +54,8 @@ lt::storage_holder CustomDiskIOThread::new_torrent(const lt::storage_params &sto
lt::storage_holder storageHolder = m_nativeDiskIO->new_torrent(storageParams, torrent);
const QString savePath = Utils::Fs::expandPathAbs(QString::fromStdString(storageParams.path));
m_storageData[storageHolder] = {
m_storageData[storageHolder] =
{
savePath
, storageParams.mapped_files ? *storageParams.mapped_files : storageParams.files
, storageParams.priorities};
@@ -196,7 +197,8 @@ void CustomDiskIOThread::handleCompleteFiles(lt::storage_index_t storage, const
const QDir saveDir {savePath};
const StorageData storageData = m_storageData[storage];
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
if ((storageData.filePriorities.end_index() > fileIndex) && (storageData.filePriorities[fileIndex] == lt::dont_download))
continue;
@@ -205,10 +207,12 @@ void CustomDiskIOThread::handleCompleteFiles(lt::storage_index_t storage, const
if (fileStorage.pad_file_at(fileIndex)) continue;
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());
QFile completeFile {saveDir.absoluteFilePath(completeFilePath)};
if (completeFile.exists()) {
if (completeFile.exists())
{
QFile incompleteFile {saveDir.absoluteFilePath(filePath)};
incompleteFile.remove();
completeFile.rename(incompleteFile.fileName());
@@ -261,7 +265,8 @@ void CustomStorage::handleCompleteFiles(const QString &savePath)
const QDir saveDir {savePath};
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
if ((m_filePriorities.end_index() > fileIndex) && (m_filePriorities[fileIndex] == lt::dont_download))
continue;
@@ -270,10 +275,12 @@ void CustomStorage::handleCompleteFiles(const QString &savePath)
if (fileStorage.pad_file_at(fileIndex)) continue;
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());
QFile completeFile {saveDir.absoluteFilePath(completeFilePath)};
if (completeFile.exists()) {
if (completeFile.exists())
{
QFile incompleteFile {saveDir.absoluteFilePath(filePath)};
incompleteFile.remove();
completeFile.rename(incompleteFile.fileName());

View File

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

View File

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

View File

@@ -36,7 +36,8 @@ namespace
{
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.pause();
}
@@ -55,7 +56,8 @@ std::shared_ptr<lt::torrent_plugin> NativeSessionExtension::new_torrent(const lt
void NativeSessionExtension::on_alert(const lt::alert *alert)
{
switch (alert->type()) {
switch (alert->type())
{
case lt::fastresume_rejected_alert::alert_type:
handleFastresumeRejectedAlert(static_cast<const lt::fastresume_rejected_alert *>(alert));
break;

View File

@@ -36,14 +36,17 @@ PeerAddress PeerAddress::parse(const QString &address)
{
QVector<QStringRef> ipPort;
if (address.startsWith('[') && address.contains("]:")) { // IPv6
if (address.startsWith('[') && address.contains("]:"))
{ // IPv6
ipPort = address.splitRef("]:");
ipPort[0] = ipPort[0].mid(1); // chop '['
}
else if (address.contains(':')) { // IPv4
else if (address.contains(':'))
{ // IPv4
ipPort = address.splitRef(':');
}
else {
else
{
return {};
}

View File

@@ -208,7 +208,8 @@ qlonglong PeerInfo::totalDownload() const
QBitArray PeerInfo::pieces() const
{
QBitArray result(m_nativeInfo.pieces.size());
for (int i = 0; i < result.size(); ++i) {
for (int i = 0; i < result.size(); ++i)
{
if (m_nativeInfo.pieces[lt::piece_index_t {i}])
result.setBit(i, true);
}
@@ -233,8 +234,10 @@ void PeerInfo::calcRelevance(const TorrentHandle *torrent)
int localMissing = 0;
int remoteHaves = 0;
for (int i = 0; i < allPieces.size(); ++i) {
if (!allPieces[i]) {
for (int i = 0; i < allPieces.size(); ++i)
{
if (!allPieces[i])
{
++localMissing;
if (peerPieces[i])
++remoteHaves;
@@ -254,14 +257,17 @@ qreal PeerInfo::relevance() const
void PeerInfo::determineFlags()
{
if (isInteresting()) {
if (isInteresting())
{
// d = Your client wants to download, but peer doesn't want to send (interested and choked)
if (isRemoteChocked()) {
if (isRemoteChocked())
{
m_flags += "d ";
m_flagsDescription += ("d = "
+ tr("Interested(local) and Choked(peer)") + '\n');
}
else {
else
{
// D = Currently downloading (interested and not choked)
m_flags += "D ";
m_flagsDescription += ("D = "
@@ -269,14 +275,17 @@ void PeerInfo::determineFlags()
}
}
if (isRemoteInterested()) {
if (isRemoteInterested())
{
// u = Peer wants your client to upload, but your client doesn't want to (interested and choked)
if (isChocked()) {
if (isChocked())
{
m_flags += "u ";
m_flagsDescription += ("u = "
+ tr("interested(peer) and choked(local)") + '\n');
}
else {
else
{
// U = Currently uploading (interested and not choked)
m_flags += "U ";
m_flagsDescription += ("U = "
@@ -285,69 +294,80 @@ void PeerInfo::determineFlags()
}
// O = Optimistic unchoke
if (optimisticUnchoke()) {
if (optimisticUnchoke())
{
m_flags += "O ";
m_flagsDescription += ("O = " + tr("optimistic unchoke") + '\n');
}
// S = Peer is snubbed
if (isSnubbed()) {
if (isSnubbed())
{
m_flags += "S ";
m_flagsDescription += ("S = " + tr("peer snubbed") + '\n');
}
// I = Peer is an incoming connection
if (!isLocalConnection()) {
if (!isLocalConnection())
{
m_flags += "I ";
m_flagsDescription += ("I = " + tr("incoming connection") + '\n');
}
// K = Peer is unchoking your client, but your client is not interested
if (!isRemoteChocked() && !isInteresting()) {
if (!isRemoteChocked() && !isInteresting())
{
m_flags += "K ";
m_flagsDescription += ("K = "
+ tr("not interested(local) and unchoked(peer)") + '\n');
}
// ? = Your client unchoked the peer but the peer is not interested
if (!isChocked() && !isRemoteInterested()) {
if (!isChocked() && !isRemoteInterested())
{
m_flags += "? ";
m_flagsDescription += ("? = "
+ tr("not interested(peer) and unchoked(local)") + '\n');
}
// X = Peer was included in peerlists obtained through Peer Exchange (PEX)
if (fromPeX()) {
if (fromPeX())
{
m_flags += "X ";
m_flagsDescription += ("X = " + tr("peer from PEX") + '\n');
}
// H = Peer was obtained through DHT
if (fromDHT()) {
if (fromDHT())
{
m_flags += "H ";
m_flagsDescription += ("H = " + tr("peer from DHT") + '\n');
}
// E = Peer is using Protocol Encryption (all traffic)
if (isRC4Encrypted()) {
if (isRC4Encrypted())
{
m_flags += "E ";
m_flagsDescription += ("E = " + tr("encrypted traffic") + '\n');
}
// e = Peer is using Protocol Encryption (handshake)
if (isPlaintextEncrypted()) {
if (isPlaintextEncrypted())
{
m_flags += "e ";
m_flagsDescription += ("e = " + tr("encrypted handshake") + '\n');
}
// P = Peer is using uTorrent uTP
if (useUTPSocket()) {
if (useUTPSocket())
{
m_flags += "P ";
m_flagsDescription += ("P = " + QString::fromUtf8(C_UTP) + '\n');
}
// L = Peer is local
if (fromLSD()) {
if (fromLSD())
{
m_flags += "L ";
m_flagsDescription += ("L = " + tr("peer from LSD") + '\n');
}

View File

@@ -58,7 +58,8 @@ bool PortForwarderImpl::isEnabled() const
void PortForwarderImpl::setEnabled(const bool enabled)
{
if (m_active != enabled) {
if (m_active != enabled)
{
if (enabled)
start();
else
@@ -71,7 +72,8 @@ void PortForwarderImpl::setEnabled(const bool enabled)
void PortForwarderImpl::addPort(const quint16 port)
{
if (!m_mappedPorts.contains(port)) {
if (!m_mappedPorts.contains(port))
{
m_mappedPorts.insert(port, {});
if (isEnabled())
m_mappedPorts[port] = {m_provider->add_port_mapping(lt::session::tcp, port, port)};
@@ -80,8 +82,10 @@ void PortForwarderImpl::addPort(const quint16 port)
void PortForwarderImpl::deletePort(const quint16 port)
{
if (m_mappedPorts.contains(port)) {
if (isEnabled()) {
if (m_mappedPorts.contains(port))
{
if (isEnabled())
{
for (const lt::port_mapping_t &portMapping : m_mappedPorts[port])
m_provider->delete_port_mapping(portMapping);
}
@@ -96,7 +100,8 @@ void PortForwarderImpl::start()
settingsPack.set_bool(lt::settings_pack::enable_upnp, true);
settingsPack.set_bool(lt::settings_pack::enable_natpmp, true);
m_provider->apply_settings(settingsPack);
for (auto i = m_mappedPorts.begin(); i != m_mappedPorts.end(); ++i) {
for (auto i = m_mappedPorts.begin(); i != m_mappedPorts.end(); ++i)
{
// quint16 port = i.key();
i.value() = {m_provider->add_port_mapping(lt::session::tcp, i.key(), i.key())};
}

View File

@@ -48,7 +48,8 @@ void ResumeDataSavingManager::save(const QString &filename, const QByteArray &da
const QString filepath = m_resumeDataDir.absoluteFilePath(filename);
QSaveFile file {filepath};
if (!file.open(QIODevice::WriteOnly) || (file.write(data) != data.size()) || !file.commit()) {
if (!file.open(QIODevice::WriteOnly) || (file.write(data) != data.size()) || !file.commit())
{
LogMsg(tr("Couldn't save data to '%1'. Error: %2")
.arg(filepath, file.errorString()), Log::CRITICAL);
}
@@ -59,14 +60,16 @@ void ResumeDataSavingManager::save(const QString &filename, const std::shared_pt
const QString filepath = m_resumeDataDir.absoluteFilePath(filename);
QSaveFile file {filepath};
if (!file.open(QIODevice::WriteOnly)) {
if (!file.open(QIODevice::WriteOnly))
{
LogMsg(tr("Couldn't save data to '%1'. Error: %2")
.arg(filepath, file.errorString()), Log::CRITICAL);
return;
}
lt::bencode(Utils::IO::FileDeviceOutputIterator {file}, *data);
if ((file.error() != QFileDevice::NoError) || !file.commit()) {
if ((file.error() != QFileDevice::NoError) || !file.commit())
{
LogMsg(tr("Couldn't save data to '%1'. Error: %2")
.arg(filepath, file.errorString()), Log::CRITICAL);
}

File diff suppressed because it is too large Load Diff

View File

@@ -36,7 +36,8 @@ SpeedMonitor::SpeedMonitor()
void SpeedMonitor::addSample(const SpeedSample &sample)
{
if (m_speedSamples.size() >= MAX_SAMPLES) {
if (m_speedSamples.size() >= MAX_SAMPLES)
{
m_sum -= m_speedSamples.front();
}

View File

@@ -71,11 +71,13 @@ quint64 Statistics::getAlltimeUL() const
void Statistics::gather()
{
const SessionStatus &ss = m_session->status();
if (ss.totalDownload > m_sessionDL) {
if (ss.totalDownload > m_sessionDL)
{
m_sessionDL = ss.totalDownload;
m_dirty = true;
}
if (ss.totalUpload > m_sessionUL) {
if (ss.totalUpload > m_sessionUL)
{
m_sessionUL = ss.totalUpload;
m_dirty = true;
}

View File

@@ -59,7 +59,8 @@ namespace
#if (LIBTORRENT_VERSION_NUM >= 20000)
lt::create_flags_t toNativeTorrentFormatFlag(const BitTorrent::TorrentFormat torrentFormat)
{
switch (torrentFormat) {
switch (torrentFormat)
{
case BitTorrent::TorrentFormat::V1:
return lt::create_torrent::v1_only;
case BitTorrent::TorrentFormat::Hybrid:
@@ -102,20 +103,24 @@ void TorrentCreatorThread::run()
emit updateProgress(0);
try {
try
{
const QString parentPath = Utils::Fs::branchPath(m_params.inputPath) + '/';
// Adding files to the torrent
lt::file_storage fs;
if (QFileInfo(m_params.inputPath).isFile()) {
if (QFileInfo(m_params.inputPath).isFile())
{
lt::add_files(fs, Utils::Fs::toNativePath(m_params.inputPath).toStdString(), fileFilter);
}
else {
else
{
// need to sort the file names by natural sort order
QStringList dirs = {m_params.inputPath};
QDirIterator dirIter(m_params.inputPath, (QDir::AllDirs | QDir::NoDotAndDotDot), QDirIterator::Subdirectories);
while (dirIter.hasNext()) {
while (dirIter.hasNext())
{
dirIter.next();
dirs += dirIter.filePath();
}
@@ -124,11 +129,13 @@ void TorrentCreatorThread::run()
QStringList fileNames;
QHash<QString, qint64> fileSizeMap;
for (const auto &dir : asConst(dirs)) {
for (const auto &dir : asConst(dirs))
{
QStringList tmpNames; // natural sort files within each dir
QDirIterator fileIter(dir, QDir::Files);
while (fileIter.hasNext()) {
while (fileIter.hasNext())
{
fileIter.next();
const QString relFilePath = fileIter.filePath().mid(parentPath.length());
@@ -154,14 +161,16 @@ void TorrentCreatorThread::run()
#endif
// Add url seeds
for (QString seed : asConst(m_params.urlSeeds)) {
for (QString seed : asConst(m_params.urlSeeds))
{
seed = seed.trimmed();
if (!seed.isEmpty())
newTorrent.add_url_seed(seed.toStdString());
}
int tier = 0;
for (const QString &tracker : asConst(m_params.trackers)) {
for (const QString &tracker : asConst(m_params.trackers))
{
if (tracker.isEmpty())
++tier;
else
@@ -195,16 +204,20 @@ void TorrentCreatorThread::run()
// create the torrent
QFile outfile {m_params.savePath};
if (!outfile.open(QIODevice::WriteOnly)) {
throw RuntimeError {tr("Create new torrent file failed. Reason: %1")
if (!outfile.open(QIODevice::WriteOnly))
{
throw RuntimeError
{tr("Create new torrent file failed. Reason: %1")
.arg(outfile.errorString())};
}
if (isInterruptionRequested()) return;
lt::bencode(Utils::IO::FileDeviceOutputIterator {outfile}, entry);
if (outfile.error() != QFileDevice::NoError) {
throw RuntimeError {tr("Create new torrent file failed. Reason: %1")
if (outfile.error() != QFileDevice::NoError)
{
throw RuntimeError
{tr("Create new torrent file failed. Reason: %1")
.arg(outfile.errorString())};
}
outfile.close();
@@ -212,7 +225,8 @@ void TorrentCreatorThread::run()
emit updateProgress(100);
emit creationSuccess(m_params.savePath, parentPath);
}
catch (const std::exception &e) {
catch (const std::exception &e)
{
emit creationFailure(e.what());
}
}

View File

@@ -126,10 +126,12 @@ TorrentHandleImpl::TorrentHandleImpl(Session *session, const lt::torrent_handle
updateStatus();
m_hash = InfoHash(m_nativeStatus.info_hash);
if (hasMetadata()) {
if (hasMetadata())
{
applyFirstLastPiecePriority(m_hasFirstLastPiecePriority);
if (!params.restored) {
if (!params.restored)
{
if (filesCount() == 1)
m_hasRootFolder = false;
}
@@ -138,11 +140,13 @@ TorrentHandleImpl::TorrentHandleImpl(Session *session, const lt::torrent_handle
// TODO: Remove the following upgrade code in v.4.4
// == BEGIN UPGRADE CODE ==
const QString spath = actualStorageLocation();
for (int i = 0; i < filesCount(); ++i) {
for (int i = 0; i < filesCount(); ++i)
{
const QString filepath = filePath(i);
// Move "unwanted" files back to their original folder
const QString parentRelPath = Utils::Fs::branchPath(filepath);
if (QDir(parentRelPath).dirName() == ".unwanted") {
if (QDir(parentRelPath).dirName() == ".unwanted")
{
const QString oldName = Utils::Fs::fileName(filepath);
const QString newRelPath = Utils::Fs::branchPath(parentRelPath);
if (newRelPath.isEmpty())
@@ -178,7 +182,8 @@ QString TorrentHandleImpl::name() const
name = QString::fromStdString(m_nativeStatus.name);
if (!name.isEmpty()) return name;
if (hasMetadata()) {
if (hasMetadata())
{
name = QString::fromStdString(m_torrentInfo.nativeInfo()->orig_files().name());
if (!name.isEmpty()) return name;
}
@@ -330,8 +335,10 @@ void TorrentHandleImpl::addTrackers(const QVector<TrackerEntry> &trackers)
QVector<TrackerEntry> newTrackers;
newTrackers.reserve(trackers.size());
for (const TrackerEntry &tracker : trackers) {
if (!currentTrackers.contains(tracker)) {
for (const TrackerEntry &tracker : trackers)
{
if (!currentTrackers.contains(tracker))
{
m_nativeHandle.add_tracker(tracker.nativeEntry());
newTrackers << tracker;
}
@@ -351,7 +358,8 @@ void TorrentHandleImpl::replaceTrackers(const QVector<TrackerEntry> &trackers)
std::vector<lt::announce_entry> nativeTrackers;
nativeTrackers.reserve(trackers.size());
for (const TrackerEntry &tracker : trackers) {
for (const TrackerEntry &tracker : trackers)
{
nativeTrackers.emplace_back(tracker.nativeEntry());
if (!currentTrackers.removeOne(tracker))
@@ -360,11 +368,13 @@ void TorrentHandleImpl::replaceTrackers(const QVector<TrackerEntry> &trackers)
m_nativeHandle.replace_trackers(nativeTrackers);
if (newTrackers.isEmpty() && currentTrackers.isEmpty()) {
if (newTrackers.isEmpty() && currentTrackers.isEmpty())
{
// when existing tracker reorders
m_session->handleTorrentTrackersChanged(this);
}
else {
else
{
if (!currentTrackers.isEmpty())
m_session->handleTorrentTrackersRemoved(this, currentTrackers);
@@ -398,9 +408,11 @@ void TorrentHandleImpl::addUrlSeeds(const QVector<QUrl> &urlSeeds)
QVector<QUrl> addedUrlSeeds;
addedUrlSeeds.reserve(urlSeeds.size());
for (const QUrl &url : urlSeeds) {
for (const QUrl &url : urlSeeds)
{
const std::string nativeUrl = url.toString().toStdString();
if (currentSeeds.find(nativeUrl) == currentSeeds.end()) {
if (currentSeeds.find(nativeUrl) == currentSeeds.end())
{
m_nativeHandle.add_url_seed(nativeUrl);
addedUrlSeeds << url;
}
@@ -417,9 +429,11 @@ void TorrentHandleImpl::removeUrlSeeds(const QVector<QUrl> &urlSeeds)
QVector<QUrl> removedUrlSeeds;
removedUrlSeeds.reserve(urlSeeds.size());
for (const QUrl &url : urlSeeds) {
for (const QUrl &url : urlSeeds)
{
const std::string nativeUrl = url.toString().toStdString();
if (currentSeeds.find(nativeUrl) != currentSeeds.end()) {
if (currentSeeds.find(nativeUrl) != currentSeeds.end())
{
m_nativeHandle.remove_url_seed(nativeUrl);
removedUrlSeeds << url;
}
@@ -443,10 +457,12 @@ bool TorrentHandleImpl::connectPeer(const PeerAddress &peerAddress)
if (ec) return false;
const lt::tcp::endpoint endpoint(addr, peerAddress.port);
try {
try
{
m_nativeHandle.connect_peer(endpoint);
}
catch (const lt::system_error &err) {
catch (const lt::system_error &err)
{
LogMsg(tr("Failed to add peer \"%1\" to torrent \"%2\". Reason: %3")
.arg(peerAddress.toString(), name(), QString::fromLocal8Bit(err.what())), Log::WARNING);
return false;
@@ -533,7 +549,8 @@ bool TorrentHandleImpl::addTag(const QString &tag)
if (!Session::isValidTag(tag))
return false;
if (!hasTag(tag)) {
if (!hasTag(tag))
{
if (!m_session->hasTag(tag))
if (!m_session->addTag(tag))
return false;
@@ -546,7 +563,8 @@ bool TorrentHandleImpl::addTag(const QString &tag)
bool TorrentHandleImpl::removeTag(const QString &tag)
{
if (m_tags.remove(tag)) {
if (m_tags.remove(tag))
{
m_session->handleTorrentTagRemoved(this, tag);
return true;
}
@@ -719,25 +737,31 @@ TorrentState TorrentHandleImpl::state() const
void TorrentHandleImpl::updateState()
{
if (m_nativeStatus.state == lt::torrent_status::checking_resume_data) {
if (m_nativeStatus.state == lt::torrent_status::checking_resume_data)
{
m_state = TorrentState::CheckingResumeData;
}
else if (isMoveInProgress()) {
else if (isMoveInProgress())
{
m_state = TorrentState::Moving;
}
else if (hasMissingFiles()) {
else if (hasMissingFiles())
{
m_state = TorrentState::MissingFiles;
}
else if (hasError()) {
else if (hasError())
{
m_state = TorrentState::Error;
}
else if ((m_nativeStatus.state == lt::torrent_status::checking_files)
&& (!isPaused() || (m_nativeStatus.flags & lt::torrent_flags::auto_managed)
|| !(m_nativeStatus.flags & lt::torrent_flags::paused))) {
|| !(m_nativeStatus.flags & lt::torrent_flags::paused)))
{
// If the torrent is not just in the "checking" state, but is being actually checked
m_state = m_hasSeedStatus ? TorrentState::CheckingUploading : TorrentState::CheckingDownloading;
}
else if (isSeed()) {
else if (isSeed())
{
if (isPaused())
m_state = TorrentState::PausedUploading;
else if (m_session->isQueueingSystemEnabled() && isQueued())
@@ -749,7 +773,8 @@ void TorrentHandleImpl::updateState()
else
m_state = TorrentState::StalledUploading;
}
else {
else
{
if (isPaused())
m_state = TorrentState::PausedDownloading;
else if (m_nativeStatus.state == lt::torrent_status::downloading_metadata)
@@ -832,14 +857,16 @@ qlonglong TorrentHandleImpl::eta() const
const SpeedSampleAvg speedAverage = m_speedMonitor.average();
if (isSeed()) {
if (isSeed())
{
const qreal maxRatioValue = maxRatio();
const int maxSeedingTimeValue = maxSeedingTime();
if ((maxRatioValue < 0) && (maxSeedingTimeValue < 0)) return MAX_ETA;
qlonglong ratioEta = MAX_ETA;
if ((speedAverage.upload > 0) && (maxRatioValue >= 0)) {
if ((speedAverage.upload > 0) && (maxRatioValue >= 0))
{
qlonglong realDL = totalDownload();
if (realDL <= 0)
@@ -850,7 +877,8 @@ qlonglong TorrentHandleImpl::eta() const
qlonglong seedingTimeEta = MAX_ETA;
if (maxSeedingTimeValue >= 0) {
if (maxSeedingTimeValue >= 0)
{
seedingTimeEta = (maxSeedingTimeValue * 60) - seedingTime();
if (seedingTimeEta < 0)
seedingTimeEta = 0;
@@ -872,7 +900,8 @@ QVector<qreal> TorrentHandleImpl::filesProgress() const
const int count = static_cast<int>(fp.size());
QVector<qreal> result;
result.reserve(count);
for (int i = 0; i < count; ++i) {
for (int i = 0; i < count; ++i)
{
const qlonglong size = fileSize(i);
if ((size <= 0) || (fp[i] == size))
result << 1;
@@ -995,7 +1024,8 @@ QVector<PeerInfo> TorrentHandleImpl::peers() const
QBitArray TorrentHandleImpl::pieces() const
{
QBitArray result(m_nativeStatus.pieces.size());
for (int i = 0; i < result.size(); ++i) {
for (int i = 0; i < result.size(); ++i)
{
if (m_nativeStatus.pieces[lt::piece_index_t {i}])
result.setBit(i, true);
}
@@ -1097,7 +1127,8 @@ qlonglong TorrentHandleImpl::nextAnnounce() const
void TorrentHandleImpl::setName(const QString &name)
{
if (m_name != name) {
if (m_name != name)
{
m_name = name;
m_session->handleTorrentNameChanged(this);
}
@@ -1105,7 +1136,8 @@ void TorrentHandleImpl::setName(const QString &name)
bool TorrentHandleImpl::setCategory(const QString &category)
{
if (m_category != category) {
if (m_category != category)
{
if (!category.isEmpty() && !m_session->categories().contains(category))
return false;
@@ -1113,7 +1145,8 @@ bool TorrentHandleImpl::setCategory(const QString &category)
m_category = category;
m_session->handleTorrentCategoryChanged(this, oldCategory);
if (m_useAutoTMM) {
if (m_useAutoTMM)
{
if (!m_session->isDisableAutoTMMWhenCategoryChanged())
move_impl(m_session->categorySavePath(m_category), MoveStorageMode::Overwrite);
else
@@ -1126,7 +1159,8 @@ bool TorrentHandleImpl::setCategory(const QString &category)
void TorrentHandleImpl::move(QString path)
{
if (m_useAutoTMM) {
if (m_useAutoTMM)
{
m_useAutoTMM = false;
m_session->handleTorrentSavingModeChanged(this);
}
@@ -1145,10 +1179,12 @@ void TorrentHandleImpl::move_impl(QString path, const MoveStorageMode mode)
if (path == savePath()) return;
path = Utils::Fs::toNativePath(path);
if (!useTempPath()) {
if (!useTempPath())
{
moveStorage(path, mode);
}
else {
else
{
m_savePath = path;
m_session->handleTorrentSavePathChanged(this);
}
@@ -1172,7 +1208,8 @@ void TorrentHandleImpl::forceRecheck()
m_hasMissingFiles = false;
m_unchecked = false;
if (isPaused()) {
if (isPaused())
{
// When "force recheck" is applied on paused torrent, we temporarily resume it
// (really we just allow libtorrent to resume it by enabling auto management for it).
m_nativeHandle.set_flags(lt::torrent_flags::stop_when_ready | lt::torrent_flags::auto_managed);
@@ -1181,11 +1218,13 @@ void TorrentHandleImpl::forceRecheck()
void TorrentHandleImpl::setSequentialDownload(const bool enable)
{
if (enable) {
if (enable)
{
m_nativeHandle.set_flags(lt::torrent_flags::sequential_download);
m_nativeStatus.flags |= lt::torrent_flags::sequential_download; // prevent return cached value
}
else {
else
{
m_nativeHandle.unset_flags(lt::torrent_flags::sequential_download);
m_nativeStatus.flags &= ~lt::torrent_flags::sequential_download; // prevent return cached value
}
@@ -1220,7 +1259,8 @@ void TorrentHandleImpl::applyFirstLastPiecePriority(const bool enabled, const QV
// Updating file priorities is an async operation in libtorrent, when we just updated it and immediately query it
// we might get the old/wrong values, so we rely on `updatedFilePrio` in this case.
for (int index = 0; index < static_cast<int>(filePriorities.size()); ++index) {
for (int index = 0; index < static_cast<int>(filePriorities.size()); ++index)
{
const lt::download_priority_t filePrio = filePriorities[index];
if (filePrio <= lt::download_priority_t {0})
continue;
@@ -1231,7 +1271,8 @@ void TorrentHandleImpl::applyFirstLastPiecePriority(const bool enabled, const QV
// worst case: AVI index = 1% of total file size (at the end of the file)
const int nNumPieces = std::ceil(fileSize(index) * 0.01 / pieceLength());
for (int i = 0; i < nNumPieces; ++i) {
for (int i = 0; i < nNumPieces; ++i)
{
piecePriorities[extremities.first() + i] = newPrio;
piecePriorities[extremities.last() - i] = newPrio;
}
@@ -1247,7 +1288,8 @@ void TorrentHandleImpl::pause()
m_speedMonitor.reset();
if (!m_isStopped) {
if (!m_isStopped)
{
m_isStopped = true;
m_session->handleTorrentPaused(this);
}
@@ -1258,12 +1300,14 @@ void TorrentHandleImpl::resume(const TorrentOperatingMode mode)
if (hasError())
m_nativeHandle.clear_error();
if (m_hasMissingFiles) {
if (m_hasMissingFiles)
{
m_hasMissingFiles = false;
m_nativeHandle.force_recheck();
}
if (m_isStopped) {
if (m_isStopped)
{
// Torrent may have been temporarily resumed to perform checking files
// so we have to ensure it will not pause after checking is done.
m_nativeHandle.unset_flags(lt::torrent_flags::stop_when_ready);
@@ -1275,7 +1319,8 @@ void TorrentHandleImpl::resume(const TorrentOperatingMode mode)
m_operatingMode = mode;
if (m_isStopped) {
if (m_isStopped)
{
m_isStopped = false;
m_session->handleTorrentResumed(this);
}
@@ -1283,7 +1328,8 @@ void TorrentHandleImpl::resume(const TorrentOperatingMode mode)
void TorrentHandleImpl::moveStorage(const QString &newPath, const MoveStorageMode mode)
{
if (m_session->addMoveTorrentStorageJob(this, newPath, mode)) {
if (m_session->addMoveTorrentStorageJob(this, newPath, mode))
{
m_storageIsMoving = true;
updateStatus();
}
@@ -1307,7 +1353,8 @@ void TorrentHandleImpl::handleMoveStorageJobFinished(const bool hasOutstandingJo
updateStatus();
const QString newPath = QString::fromStdString(m_nativeStatus.save_path);
if (!useTempPath() && (newPath != m_savePath)) {
if (!useTempPath() && (newPath != m_savePath))
{
m_savePath = newPath;
m_session->handleTorrentSavePathChanged(this);
}
@@ -1363,14 +1410,16 @@ void TorrentHandleImpl::handleTorrentCheckedAlert(const lt::torrent_checked_aler
Q_UNUSED(p);
qDebug("\"%s\" have just finished checking", qUtf8Printable(name()));
if (m_fastresumeDataRejected && !m_hasMissingFiles) {
if (m_fastresumeDataRejected && !m_hasMissingFiles)
{
saveResumeData();
m_fastresumeDataRejected = false;
}
updateStatus();
if (!m_hasMissingFiles) {
if (!m_hasMissingFiles)
{
if ((progress() < 1.0) && (wantedSize() > 0))
m_hasSeedStatus = false;
else if (progress() == 1.0)
@@ -1398,12 +1447,14 @@ void TorrentHandleImpl::handleTorrentFinishedAlert(const lt::torrent_finished_al
manageIncompleteFiles();
const bool recheckTorrentsOnCompletion = Preferences::instance()->recheckTorrentsOnCompletion();
if (isMoveInProgress() || (m_renameCount > 0)) {
if (isMoveInProgress() || (m_renameCount > 0))
{
if (recheckTorrentsOnCompletion)
m_moveFinishedTriggers.append([this]() { forceRecheck(); });
m_moveFinishedTriggers.append([this]() { m_session->handleTorrentFinished(this); });
}
else {
else
{
if (recheckTorrentsOnCompletion && m_unchecked)
forceRecheck();
m_session->handleTorrentFinished(this);
@@ -1422,18 +1473,22 @@ void TorrentHandleImpl::handleTorrentResumedAlert(const lt::torrent_resumed_aler
void TorrentHandleImpl::handleSaveResumeDataAlert(const lt::save_resume_data_alert *p)
{
if (p && !m_hasMissingFiles) {
if (p && !m_hasMissingFiles)
{
// Update recent resume data
m_ltAddTorrentParams = p->params;
}
if (!m_isStopped) {
if (!m_isStopped)
{
// Torrent can be actually "running" but temporarily "paused" to perform some
// service jobs behind the scenes so we need to restore it as "running"
if (m_operatingMode == TorrentOperatingMode::AutoManaged) {
if (m_operatingMode == TorrentOperatingMode::AutoManaged)
{
m_ltAddTorrentParams.flags |= lt::torrent_flags::auto_managed;
}
else {
else
{
m_ltAddTorrentParams.flags &= ~lt::torrent_flags::paused;
m_ltAddTorrentParams.flags &= ~lt::torrent_flags::auto_managed;
}
@@ -1449,7 +1504,8 @@ void TorrentHandleImpl::handleSaveResumeDataAlert(const lt::save_resume_data_ale
// TODO: The following code is deprecated. Remove after several releases in 4.3.x.
// === BEGIN DEPRECATED CODE === //
const bool useDummyResumeData = !p;
if (useDummyResumeData) {
if (useDummyResumeData)
{
updateStatus();
resumeData["qBt-magnetUri"] = createMagnetURI().toStdString();
@@ -1489,12 +1545,14 @@ void TorrentHandleImpl::handleFastResumeRejectedAlert(const lt::fastresume_rejec
{
m_fastresumeDataRejected = true;
if (p->error.value() == lt::errors::mismatching_file_size) {
if (p->error.value() == lt::errors::mismatching_file_size)
{
// Mismatching file size (files were probably moved)
m_hasMissingFiles = true;
LogMsg(tr("File sizes mismatch for torrent '%1'. Cannot proceed further.").arg(name()), Log::CRITICAL);
}
else {
else
{
LogMsg(tr("Fast resume data was rejected for torrent '%1'. Reason: %2. Checking again...")
.arg(name(), QString::fromStdString(p->message())), Log::WARNING);
}
@@ -1527,13 +1585,15 @@ void TorrentHandleImpl::handleFileRenamedAlert(const lt::file_renamed_alert *p)
#endif
int pathIdx = 0;
while ((pathIdx < oldPathParts.size()) && (pathIdx < newPathParts.size())) {
while ((pathIdx < oldPathParts.size()) && (pathIdx < newPathParts.size()))
{
if (oldPathParts[pathIdx].compare(newPathParts[pathIdx], caseSensitivity) != 0)
break;
++pathIdx;
}
for (int i = (oldPathParts.size() - 1); i >= pathIdx; --i) {
for (int i = (oldPathParts.size() - 1); i >= pathIdx; --i)
{
QDir().rmdir(savePath() + Utils::String::join(oldPathParts, QLatin1String("/")));
oldPathParts.removeLast();
}
@@ -1571,9 +1631,11 @@ void TorrentHandleImpl::handleFileCompletedAlert(const lt::file_completed_alert
m_torrentInfo = TorrentInfo {m_nativeHandle.torrent_file()};
qDebug("A file completed download in torrent \"%s\"", qUtf8Printable(name()));
if (m_session->isAppendExtensionEnabled()) {
if (m_session->isAppendExtensionEnabled())
{
QString name = filePath(static_cast<LTUnderlyingType<lt::file_index_t>>(p->index));
if (name.endsWith(QB_EXT)) {
if (name.endsWith(QB_EXT))
{
const QString oldName = name;
name.chop(QB_EXT.size());
qDebug("Renaming %s to %s", qUtf8Printable(oldName), qUtf8Printable(name));
@@ -1627,7 +1689,8 @@ void TorrentHandleImpl::handleAppendExtensionToggled()
void TorrentHandleImpl::handleAlert(const lt::alert *a)
{
switch (a->type()) {
switch (a->type())
{
case lt::file_renamed_alert::alert_type:
handleFileRenamedAlert(static_cast<const lt::file_renamed_alert*>(a));
break;
@@ -1680,22 +1743,28 @@ void TorrentHandleImpl::manageIncompleteFiles()
{
const bool isAppendExtensionEnabled = m_session->isAppendExtensionEnabled();
const QVector<qreal> fp = filesProgress();
if (fp.size() != filesCount()) {
if (fp.size() != filesCount())
{
qDebug() << "skip manageIncompleteFiles because of invalid torrent meta-data or empty file-progress";
return;
}
for (int i = 0; i < filesCount(); ++i) {
for (int i = 0; i < filesCount(); ++i)
{
QString name = filePath(i);
if (isAppendExtensionEnabled && (fileSize(i) > 0) && (fp[i] < 1)) {
if (!name.endsWith(QB_EXT)) {
if (isAppendExtensionEnabled && (fileSize(i) > 0) && (fp[i] < 1))
{
if (!name.endsWith(QB_EXT))
{
const QString newName = name + QB_EXT;
qDebug() << "Renaming" << name << "to" << newName;
renameFile(i, newName);
}
}
else {
if (name.endsWith(QB_EXT)) {
else
{
if (name.endsWith(QB_EXT))
{
const QString oldName = name;
name.chop(QB_EXT.size());
qDebug() << "Renaming" << oldName << "to" << name;
@@ -1722,8 +1791,10 @@ void TorrentHandleImpl::adjustActualSavePath_impl()
if (targetDir == currentDir) return;
if (!needUseTempDir) {
if ((currentDir == tempDir) && (currentDir != QDir {m_session->tempPath()})) {
if (!needUseTempDir)
{
if ((currentDir == tempDir) && (currentDir != QDir {m_session->tempPath()}))
{
// torrent without root folder still has it in its temporary save path
// so its temp path isn't equal to temp path root
const QString currentDirPath = currentDir.absolutePath();
@@ -1790,7 +1861,8 @@ void TorrentHandleImpl::setRatioLimit(qreal limit)
else if (limit > MAX_RATIO)
limit = MAX_RATIO;
if (m_ratioLimit != limit) {
if (m_ratioLimit != limit)
{
m_ratioLimit = limit;
m_session->handleTorrentShareLimitChanged(this);
}
@@ -1803,7 +1875,8 @@ void TorrentHandleImpl::setSeedingTimeLimit(int limit)
else if (limit > MAX_SEEDING_TIME)
limit = MAX_SEEDING_TIME;
if (m_seedingTimeLimit != limit) {
if (m_seedingTimeLimit != limit)
{
m_seedingTimeLimit = limit;
m_session->handleTorrentShareLimitChanged(this);
}
@@ -1846,10 +1919,12 @@ void TorrentHandleImpl::prioritizeFiles(const QVector<DownloadPriority> &priorit
// 'torrent_finished_alert' and eg show tray notifications
const QVector<qreal> progress = filesProgress();
const QVector<DownloadPriority> oldPriorities = filePriorities();
for (int i = 0; i < oldPriorities.size(); ++i) {
for (int i = 0; i < oldPriorities.size(); ++i)
{
if ((oldPriorities[i] == DownloadPriority::Ignored)
&& (priorities[i] > DownloadPriority::Ignored)
&& (progress[i] < 1.0)) {
&& (progress[i] < 1.0))
{
m_hasSeedStatus = false;
break;
}
@@ -1875,7 +1950,8 @@ QVector<qreal> TorrentHandleImpl::availableFileFractions() const
QVector<qreal> res;
res.reserve(filesCount);
const TorrentInfo info = this->info();
for (int i = 0; i < filesCount; ++i) {
for (int i = 0; i < filesCount; ++i)
{
const TorrentInfo::PieceRange filePieces = info.filePieces(i);
int availablePieces = 0;

View File

@@ -77,14 +77,16 @@ TorrentInfo TorrentInfo::load(const QByteArray &data, QString *error) noexcept
lt::error_code ec;
const lt::bdecode_node node = lt::bdecode(data, ec
, nullptr, depthLimit, tokenLimit);
if (ec) {
if (ec)
{
if (error)
*error = QString::fromStdString(ec.message());
return TorrentInfo();
}
TorrentInfo info {std::shared_ptr<lt::torrent_info>(new lt::torrent_info(node, ec))};
if (ec) {
if (ec)
{
if (error)
*error = QString::fromStdString(ec.message());
return TorrentInfo();
@@ -99,28 +101,33 @@ TorrentInfo TorrentInfo::loadFromFile(const QString &path, QString *error) noexc
error->clear();
QFile file {path};
if (!file.open(QIODevice::ReadOnly)) {
if (!file.open(QIODevice::ReadOnly))
{
if (error)
*error = file.errorString();
return TorrentInfo();
}
if (file.size() > MAX_TORRENT_SIZE) {
if (file.size() > MAX_TORRENT_SIZE)
{
if (error)
*error = tr("File size exceeds max limit %1").arg(Utils::Misc::friendlyUnit(MAX_TORRENT_SIZE));
return TorrentInfo();
}
QByteArray data;
try {
try
{
data = file.readAll();
}
catch (const std::bad_alloc &e) {
catch (const std::bad_alloc &e)
{
if (error)
*error = tr("Torrent file read error: %1").arg(e.what());
return TorrentInfo();
}
if (data.size() != file.size()) {
if (data.size() != file.size())
{
if (error)
*error = tr("Torrent file read error: size mismatch");
return TorrentInfo();
@@ -284,7 +291,8 @@ QVector<QUrl> TorrentInfo::urlSeeds() const
QVector<QUrl> urlSeeds;
urlSeeds.reserve(nativeWebSeeds.size());
for (const lt::web_seed_entry &webSeed : nativeWebSeeds) {
for (const lt::web_seed_entry &webSeed : nativeWebSeeds)
{
if (webSeed.type == lt::web_seed_entry::url_seed)
urlSeeds.append(QUrl(webSeed.url.c_str()));
}
@@ -353,7 +361,8 @@ TorrentInfo::PieceRange TorrentInfo::filePieces(const QString &file) const
return {};
const int index = fileIndex(file);
if (index == -1) {
if (index == -1)
{
qDebug() << "Filename" << file << "was not found in torrent" << name();
return {};
}
@@ -365,7 +374,8 @@ TorrentInfo::PieceRange TorrentInfo::filePieces(const int fileIndex) const
if (!isValid())
return {};
if ((fileIndex < 0) || (fileIndex >= filesCount())) {
if ((fileIndex < 0) || (fileIndex >= filesCount()))
{
qDebug() << "File index (" << fileIndex << ") is out of range for torrent" << name();
return {};
}
@@ -402,7 +412,8 @@ int TorrentInfo::fileIndex(const QString &fileName) const
QString TorrentInfo::rootFolder() const
{
QString rootFolder;
for (int i = 0; i < filesCount(); ++i) {
for (int i = 0; i < filesCount(); ++i)
{
const QString filePath = this->filePath(i);
if (QDir::isAbsolutePath(filePath)) continue;
@@ -433,7 +444,8 @@ void TorrentInfo::stripRootFolder()
// Solution for case of renamed root folder
const QString path = filePath(0);
const std::string newName = path.left(path.indexOf('/')).toStdString();
if (files.name() != newName) {
if (files.name() != newName)
{
files.set_name(newName);
for (int i = 0; i < files.num_files(); ++i)
files.rename_file(lt::file_index_t {i}, files.file_path(lt::file_index_t {i}));

View File

@@ -92,9 +92,11 @@ namespace
QByteArray toBigEndianByteArray(const QHostAddress &addr)
{
// translate IP address to a sequence of bytes in big-endian order
switch (addr.protocol()) {
switch (addr.protocol())
{
case QAbstractSocket::IPv4Protocol:
case QAbstractSocket::AnyIPProtocol: {
case QAbstractSocket::AnyIPProtocol:
{
const quint32 ipv4 = addr.toIPv4Address();
QByteArray ret;
ret.append(static_cast<char>((ipv4 >> 24) & 0xFF))
@@ -104,7 +106,8 @@ namespace
return ret;
}
case QAbstractSocket::IPv6Protocol: {
case QAbstractSocket::IPv6Protocol:
{
const Q_IPV6ADDR ipv6 = addr.toIPv6Address();
QByteArray ret;
for (const quint8 i : ipv6.c)
@@ -162,7 +165,8 @@ struct Tracker::TrackerAnnounceRequest
void Tracker::TorrentStats::setPeer(const Peer &peer)
{
// always replace existing peer
if (!removePeer(peer)) {
if (!removePeer(peer))
{
// Too many peers, remove a random one
if (peers.size() >= MAX_PEERS_PER_TORRENT)
removePeer(*peers.begin());
@@ -198,8 +202,10 @@ bool Tracker::start()
const QHostAddress ip = QHostAddress::Any;
const int port = Preferences::instance()->getTrackerPort();
if (m_server->isListening()) {
if (m_server->serverPort() == port) {
if (m_server->isListening())
{
if (m_server->serverPort() == port)
{
// Already listening on the right port, just return
return true;
}
@@ -211,11 +217,13 @@ bool Tracker::start()
// Listen on the predefined port
const bool listenSuccess = m_server->listen(ip, port);
if (listenSuccess) {
if (listenSuccess)
{
LogMsg(tr("Embedded Tracker: Now listening on IP: %1, port: %2")
.arg(ip.toString(), QString::number(port)), Log::INFO);
}
else {
else
{
LogMsg(tr("Embedded Tracker: Unable to bind to IP: %1, port: %2. Reason: %3")
.arg(ip.toString(), QString::number(port), m_server->errorString())
, Log::WARNING);
@@ -233,7 +241,8 @@ Http::Response Tracker::processRequest(const Http::Request &request, const Http:
status(200);
try {
try
{
// Is it a GET request?
if (request.method != Http::HEADER_REQUEST_METHOD_GET)
throw MethodNotAllowedHTTPError();
@@ -243,16 +252,19 @@ Http::Response Tracker::processRequest(const Http::Request &request, const Http:
else
throw NotFoundHTTPError();
}
catch (const HTTPError &error) {
catch (const HTTPError &error)
{
status(error.statusCode(), error.statusText());
if (!error.message().isEmpty())
print(error.message(), Http::CONTENT_TYPE_TXT);
}
catch (const TrackerError &error) {
catch (const TrackerError &error)
{
clear(); // clear response
status(200);
const lt::entry::dictionary_type bencodedEntry = {
const lt::entry::dictionary_type bencodedEntry =
{
{ANNOUNCE_RESPONSE_FAILURE_REASON, {error.what()}}
};
QByteArray reply;
@@ -312,7 +324,8 @@ void Tracker::processAnnounceRequest()
// 4. numwant
const auto numWantIter = queryParams.find(ANNOUNCE_REQUEST_NUM_WANT);
if (numWantIter != queryParams.end()) {
if (numWantIter != queryParams.end())
{
const int num = numWantIter->toInt();
if (num < 0)
throw TrackerError("Invalid \"numwant\" parameter");
@@ -348,15 +361,18 @@ void Tracker::processAnnounceRequest()
|| (announceReq.event == ANNOUNCE_REQUEST_EVENT_EMPTY)
|| (announceReq.event == ANNOUNCE_REQUEST_EVENT_COMPLETED)
|| (announceReq.event == ANNOUNCE_REQUEST_EVENT_STARTED)
|| (announceReq.event == ANNOUNCE_REQUEST_EVENT_PAUSED)) {
|| (announceReq.event == ANNOUNCE_REQUEST_EVENT_PAUSED))
{
// [BEP-21] Extension for partial seeds
// (partial support - we don't support BEP-48 so the part that concerns that is not supported)
registerPeer(announceReq);
}
else if (announceReq.event == ANNOUNCE_REQUEST_EVENT_STOPPED) {
else if (announceReq.event == ANNOUNCE_REQUEST_EVENT_STOPPED)
{
unregisterPeer(announceReq);
}
else {
else
{
throw TrackerError("Invalid \"event\" parameter");
}
@@ -365,7 +381,8 @@ void Tracker::processAnnounceRequest()
void Tracker::registerPeer(const TrackerAnnounceRequest &announceReq)
{
if (!m_torrents.contains(announceReq.infoHash)) {
if (!m_torrents.contains(announceReq.infoHash))
{
// Reached max size, remove a random torrent
if (m_torrents.size() >= MAX_TORRENTS)
m_torrents.erase(m_torrents.begin());
@@ -390,7 +407,8 @@ void Tracker::prepareAnnounceResponse(const TrackerAnnounceRequest &announceReq)
{
const TorrentStats &torrentStats = m_torrents[announceReq.infoHash];
lt::entry::dictionary_type replyDict {
lt::entry::dictionary_type replyDict
{
{ANNOUNCE_RESPONSE_INTERVAL, ANNOUNCE_INTERVAL},
{ANNOUNCE_RESPONSE_COMPLETE, torrentStats.seeders},
{ANNOUNCE_RESPONSE_INCOMPLETE, (torrentStats.peers.size() - torrentStats.seeders)},
@@ -402,13 +420,16 @@ void Tracker::prepareAnnounceResponse(const TrackerAnnounceRequest &announceReq)
// peer list
// [BEP-7] IPv6 Tracker Extension (partial support - only the part that concerns BEP-23)
// [BEP-23] Tracker Returns Compact Peer Lists
if (announceReq.compact) {
if (announceReq.compact)
{
lt::entry::string_type peers;
lt::entry::string_type peers6;
if (announceReq.event != ANNOUNCE_REQUEST_EVENT_STOPPED) {
if (announceReq.event != ANNOUNCE_REQUEST_EVENT_STOPPED)
{
int counter = 0;
for (const Peer &peer : asConst(torrentStats.peers)) {
for (const Peer &peer : asConst(torrentStats.peers))
{
if (counter++ >= announceReq.numwant)
break;
@@ -423,16 +444,20 @@ void Tracker::prepareAnnounceResponse(const TrackerAnnounceRequest &announceReq)
if (!peers6.empty())
replyDict[ANNOUNCE_RESPONSE_PEERS6] = peers6;
}
else {
else
{
lt::entry::list_type peerList;
if (announceReq.event != ANNOUNCE_REQUEST_EVENT_STOPPED) {
if (announceReq.event != ANNOUNCE_REQUEST_EVENT_STOPPED)
{
int counter = 0;
for (const Peer &peer : torrentStats.peers) {
for (const Peer &peer : torrentStats.peers)
{
if (counter++ >= announceReq.numwant)
break;
lt::entry::dictionary_type peerDict = {
lt::entry::dictionary_type peerDict =
{
{ANNOUNCE_RESPONSE_PEERS_IP, peer.address},
{ANNOUNCE_RESPONSE_PEERS_PORT, peer.port}
};

View File

@@ -107,7 +107,8 @@ void TrackerEntry::setTier(const int value)
int TrackerEntry::numSeeds() const
{
int value = -1;
for (const lt::announce_endpoint &endpoint : nativeEntry().endpoints) {
for (const lt::announce_endpoint &endpoint : nativeEntry().endpoints)
{
#if (LIBTORRENT_VERSION_NUM >= 20000)
for (const lt::announce_infohash &infoHash : endpoint.info_hashes)
value = std::max(value, infoHash.scrape_complete);
@@ -121,7 +122,8 @@ int TrackerEntry::numSeeds() const
int TrackerEntry::numLeeches() const
{
int value = -1;
for (const lt::announce_endpoint &endpoint : nativeEntry().endpoints) {
for (const lt::announce_endpoint &endpoint : nativeEntry().endpoints)
{
#if (LIBTORRENT_VERSION_NUM >= 20000)
for (const lt::announce_infohash &infoHash : endpoint.info_hashes)
value = std::max(value, infoHash.scrape_incomplete);
@@ -135,7 +137,8 @@ int TrackerEntry::numLeeches() const
int TrackerEntry::numDownloaded() const
{
int value = -1;
for (const lt::announce_endpoint &endpoint : nativeEntry().endpoints) {
for (const lt::announce_endpoint &endpoint : nativeEntry().endpoints)
{
#if (LIBTORRENT_VERSION_NUM >= 20000)
for (const lt::announce_infohash &infoHash : endpoint.info_hashes)
value = std::max(value, infoHash.scrape_downloaded);

View File

@@ -76,7 +76,8 @@ void FileSystemWatcher::addPath(const QString &path)
if (!dir.exists()) return;
// Check if the path points to a network file system or not
if (Utils::Fs::isNetworkFileSystem(path)) {
if (Utils::Fs::isNetworkFileSystem(path))
{
// Network mode
LogMsg(tr("Watching remote folder: \"%1\"").arg(Utils::Fs::toNativePath(path)));
m_watchedFolders << dir;
@@ -94,7 +95,8 @@ void FileSystemWatcher::addPath(const QString &path)
void FileSystemWatcher::removePath(const QString &path)
{
if (m_watchedFolders.removeOne(path)) {
if (m_watchedFolders.removeOne(path))
{
if (m_watchedFolders.isEmpty())
m_watchTimer.stop();
return;
@@ -125,12 +127,14 @@ void FileSystemWatcher::processPartialTorrents()
if (!QFile::exists(torrentPath))
return true;
if (BitTorrent::TorrentInfo::loadFromFile(torrentPath).isValid()) {
if (BitTorrent::TorrentInfo::loadFromFile(torrentPath).isValid())
{
noLongerPartial << torrentPath;
return true;
}
if (value >= MAX_PARTIAL_RETRIES) {
if (value >= MAX_PARTIAL_RETRIES)
{
QFile::rename(torrentPath, torrentPath + ".qbt_rejected");
return true;
}
@@ -140,11 +144,13 @@ void FileSystemWatcher::processPartialTorrents()
});
// Stop the partial timer if necessary
if (m_partialTorrents.empty()) {
if (m_partialTorrents.empty())
{
m_partialTorrentTimer.stop();
qDebug("No longer any partial torrent.");
}
else {
else
{
qDebug("Still %d partial torrents after delayed processing.", m_partialTorrents.count());
m_partialTorrentTimer.start(WATCH_INTERVAL);
}
@@ -158,7 +164,8 @@ void FileSystemWatcher::processTorrentsInDir(const QDir &dir)
{
QStringList torrents;
const QStringList files = dir.entryList({"*.torrent", "*.magnet"}, QDir::Files);
for (const QString &file : files) {
for (const QString &file : files)
{
const QString fileAbsPath = dir.absoluteFilePath(file);
if (file.endsWith(".magnet", Qt::CaseInsensitive))
torrents << fileAbsPath;

View File

@@ -59,13 +59,17 @@ void Connection::read()
m_idleTimer.restart();
m_receivedData.append(m_socket->readAll());
while (!m_receivedData.isEmpty()) {
while (!m_receivedData.isEmpty())
{
const RequestParser::ParseResult result = RequestParser::parse(m_receivedData);
switch (result.status) {
case RequestParser::ParseStatus::Incomplete: {
switch (result.status)
{
case RequestParser::ParseStatus::Incomplete:
{
const long bufferLimit = RequestParser::MAX_CONTENT_SIZE * 1.1; // some margin for headers
if (m_receivedData.size() > bufferLimit) {
if (m_receivedData.size() > bufferLimit)
{
Logger::instance()->addMessage(tr("Http request size exceeds limitation, closing socket. Limit: %1, IP: %2")
.arg(bufferLimit).arg(m_socket->peerAddress().toString()), Log::WARNING);
@@ -78,7 +82,8 @@ void Connection::read()
}
return;
case RequestParser::ParseStatus::BadRequest: {
case RequestParser::ParseStatus::BadRequest:
{
Logger::instance()->addMessage(tr("Bad Http request, closing socket. IP: %1")
.arg(m_socket->peerAddress().toString()), Log::WARNING);
@@ -90,7 +95,8 @@ void Connection::read()
}
return;
case RequestParser::ParseStatus::OK: {
case RequestParser::ParseStatus::OK:
{
const Environment env {m_socket->localAddress(), m_socket->localPort(), m_socket->peerAddress(), m_socket->peerPort()};
Response resp = m_requestHandler->processRequest(result.request, env);
@@ -133,7 +139,8 @@ bool Connection::acceptsGzipEncoding(QString codings)
const auto isCodingAvailable = [](const QVector<QStringRef> &list, const QString &encoding) -> bool
{
for (const QStringRef &str : list) {
for (const QStringRef &str : list)
{
if (!str.startsWith(encoding))
continue;

View File

@@ -61,7 +61,8 @@ namespace
{
// [rfc7230] 3.2. Header Fields
const int i = line.indexOf(':');
if (i <= 0) {
if (i <= 0)
{
qWarning() << Q_FUNC_INFO << "invalid http header:" << line;
return false;
}
@@ -88,13 +89,15 @@ RequestParser::ParseResult RequestParser::doParse(const QByteArray &data)
{
// we don't handle malformed requests which use double `LF` as delimiter
const int headerEnd = data.indexOf(EOH);
if (headerEnd < 0) {
if (headerEnd < 0)
{
qDebug() << Q_FUNC_INFO << "incomplete request";
return {ParseStatus::Incomplete, Request(), 0};
}
const QString httpHeaders = QString::fromLatin1(data.constData(), headerEnd);
if (!parseStartLines(httpHeaders)) {
if (!parseStartLines(httpHeaders))
{
qWarning() << Q_FUNC_INFO << "header parsing error";
return {ParseStatus::BadRequest, Request(), 0};
}
@@ -104,26 +107,32 @@ RequestParser::ParseResult RequestParser::doParse(const QByteArray &data)
// handle supported methods
if ((m_request.method == HEADER_REQUEST_METHOD_GET) || (m_request.method == HEADER_REQUEST_METHOD_HEAD))
return {ParseStatus::OK, m_request, headerLength};
if (m_request.method == HEADER_REQUEST_METHOD_POST) {
if (m_request.method == HEADER_REQUEST_METHOD_POST)
{
bool ok = false;
const int contentLength = m_request.headers[HEADER_CONTENT_LENGTH].toInt(&ok);
if (!ok || (contentLength < 0)) {
if (!ok || (contentLength < 0))
{
qWarning() << Q_FUNC_INFO << "bad request: content-length invalid";
return {ParseStatus::BadRequest, Request(), 0};
}
if (contentLength > MAX_CONTENT_SIZE) {
if (contentLength > MAX_CONTENT_SIZE)
{
qWarning() << Q_FUNC_INFO << "bad request: message too long";
return {ParseStatus::BadRequest, Request(), 0};
}
if (contentLength > 0) {
if (contentLength > 0)
{
const QByteArray httpBodyView = midView(data, headerLength, contentLength);
if (httpBodyView.length() < contentLength) {
if (httpBodyView.length() < contentLength)
{
qDebug() << Q_FUNC_INFO << "incomplete request";
return {ParseStatus::Incomplete, Request(), 0};
}
if (!parsePostMessage(httpBodyView)) {
if (!parsePostMessage(httpBodyView))
{
qWarning() << Q_FUNC_INFO << "message body parsing error";
return {ParseStatus::BadRequest, Request(), 0};
}
@@ -143,12 +152,15 @@ bool RequestParser::parseStartLines(const QString &data)
// [rfc7230] 3.2.2. Field Order
QStringList requestLines;
for (const auto &line : lines) {
if (line.at(0).isSpace() && !requestLines.isEmpty()) {
for (const auto &line : lines)
{
if (line.at(0).isSpace() && !requestLines.isEmpty())
{
// continuation of previous line
requestLines.last() += line.toString();
}
else {
else
{
requestLines += line.toString();
}
}
@@ -159,7 +171,8 @@ bool RequestParser::parseStartLines(const QString &data)
if (!parseRequestLine(requestLines[0]))
return false;
for (auto i = ++(requestLines.begin()); i != requestLines.end(); ++i) {
for (auto i = ++(requestLines.begin()); i != requestLines.end(); ++i)
{
if (!parseHeaderLine(*i, m_request.headers))
return false;
}
@@ -174,7 +187,8 @@ bool RequestParser::parseRequestLine(const QString &line)
const QRegularExpression re(QLatin1String("^([A-Z]+)\\s+(\\S+)\\s+HTTP\\/(\\d\\.\\d)$"));
const QRegularExpressionMatch match = re.match(line);
if (!match.hasMatch()) {
if (!match.hasMatch())
{
qWarning() << Q_FUNC_INFO << "invalid http header:" << line;
return false;
}
@@ -189,12 +203,14 @@ bool RequestParser::parseRequestLine(const QString &line)
m_request.path = QString::fromUtf8(QByteArray::fromPercentEncoding(pathComponent));
if (sepPos >= 0) {
if (sepPos >= 0)
{
const QByteArray query = midView(url, (sepPos + 1));
// [rfc3986] 2.4 When to Encode or Decode
// URL components should be separated before percent-decoding
for (const QByteArray &param : asConst(splitToViews(query, "&"))) {
for (const QByteArray &param : asConst(splitToViews(query, "&")))
{
const int eqCharPos = param.indexOf('=');
if (eqCharPos <= 0) continue; // ignores params without name
@@ -222,12 +238,14 @@ bool RequestParser::parsePostMessage(const QByteArray &data)
const QString contentTypeLower = contentType.toLower();
// application/x-www-form-urlencoded
if (contentTypeLower.startsWith(CONTENT_TYPE_FORM_ENCODED)) {
if (contentTypeLower.startsWith(CONTENT_TYPE_FORM_ENCODED))
{
// [URL Standard] 5.1 application/x-www-form-urlencoded parsing
const QByteArray processedData = QByteArray(data).replace('+', ' ');
QListIterator<QStringPair> i(QUrlQuery(processedData).queryItems(QUrl::FullyDecoded));
while (i.hasNext()) {
while (i.hasNext())
{
const QStringPair pair = i.next();
m_request.posts[pair.first] = pair.second;
}
@@ -236,19 +254,22 @@ bool RequestParser::parsePostMessage(const QByteArray &data)
}
// multipart/form-data
if (contentTypeLower.startsWith(CONTENT_TYPE_FORM_DATA)) {
if (contentTypeLower.startsWith(CONTENT_TYPE_FORM_DATA))
{
// [rfc2046] 5.1.1. Common Syntax
// find boundary delimiter
const QLatin1String boundaryFieldName("boundary=");
const int idx = contentType.indexOf(boundaryFieldName);
if (idx < 0) {
if (idx < 0)
{
qWarning() << Q_FUNC_INFO << "Could not find boundary in multipart/form-data header!";
return false;
}
const QByteArray delimiter = Utils::String::unquote(contentType.midRef(idx + boundaryFieldName.size())).toLatin1();
if (delimiter.isEmpty()) {
if (delimiter.isEmpty())
{
qWarning() << Q_FUNC_INFO << "boundary delimiter field empty!";
return false;
}
@@ -256,7 +277,8 @@ bool RequestParser::parsePostMessage(const QByteArray &data)
// split data by "dash-boundary"
const QByteArray dashDelimiter = QByteArray("--") + delimiter + CRLF;
QVector<QByteArray> multipart = splitToViews(data, dashDelimiter, QString::SkipEmptyParts);
if (multipart.isEmpty()) {
if (multipart.isEmpty())
{
qWarning() << Q_FUNC_INFO << "multipart empty";
return false;
}
@@ -279,7 +301,8 @@ bool RequestParser::parseFormData(const QByteArray &data)
{
const QVector<QByteArray> list = splitToViews(data, EOH, QString::KeepEmptyParts);
if (list.size() != 2) {
if (list.size() != 2)
{
qWarning() << Q_FUNC_INFO << "multipart/form-data format error";
return false;
}
@@ -289,12 +312,15 @@ bool RequestParser::parseFormData(const QByteArray &data)
HeaderMap headersMap;
const QVector<QStringRef> headerLines = headers.splitRef(CRLF, QString::SkipEmptyParts);
for (const auto &line : headerLines) {
if (line.trimmed().startsWith(HEADER_CONTENT_DISPOSITION, Qt::CaseInsensitive)) {
for (const auto &line : headerLines)
{
if (line.trimmed().startsWith(HEADER_CONTENT_DISPOSITION, Qt::CaseInsensitive))
{
// extract out filename & name
const QVector<QStringRef> directives = line.split(';', QString::SkipEmptyParts);
for (const auto &directive : directives) {
for (const auto &directive : directives)
{
const int idx = directive.indexOf('=');
if (idx < 0)
continue;
@@ -304,7 +330,8 @@ bool RequestParser::parseFormData(const QByteArray &data)
headersMap[name] = value;
}
}
else {
else
{
if (!parseHeaderLine(line.toString(), headersMap))
return false;
}
@@ -314,13 +341,16 @@ bool RequestParser::parseFormData(const QByteArray &data)
const QLatin1String filename("filename");
const QLatin1String name("name");
if (headersMap.contains(filename)) {
if (headersMap.contains(filename))
{
m_request.files.append({headersMap[filename], headersMap[HEADER_CONTENT_TYPE], payload});
}
else if (headersMap.contains(name)) {
else if (headersMap.contains(name))
{
m_request.posts[headersMap[name]] = payload;
}
else {
else
{
// malformed
qWarning() << Q_FUNC_INFO << "multipart/form-data header error";
return false;

View File

@@ -93,12 +93,14 @@ void Server::incomingConnection(const qintptr socketDescriptor)
else
serverSocket = new QTcpSocket(this);
if (!serverSocket->setSocketDescriptor(socketDescriptor)) {
if (!serverSocket->setSocketDescriptor(socketDescriptor))
{
delete serverSocket;
return;
}
if (m_https) {
if (m_https)
{
static_cast<QSslSocket *>(serverSocket)->setProtocol(QSsl::SecureProtocols);
static_cast<QSslSocket *>(serverSocket)->setPrivateKey(m_key);
static_cast<QSslSocket *>(serverSocket)->setLocalCertificateChain(m_certificates);
@@ -134,7 +136,8 @@ bool Server::setupHttps(const QByteArray &certificates, const QByteArray &privat
const QList<QSslCertificate> certs {Utils::Net::loadSSLCertificate(certificates)};
const QSslKey key {Utils::Net::loadSSLKey(privateKey)};
if (certs.isEmpty() || key.isNull()) {
if (certs.isEmpty() || key.isNull())
{
disableHttps();
return false;
}

View File

@@ -56,7 +56,8 @@ DNSUpdater::DNSUpdater(QObject *parent)
// Check lastUpdate to avoid flooding
if (!m_lastIPCheckTime.isValid()
|| (m_lastIPCheckTime.secsTo(QDateTime::currentDateTime()) * 1000 > IP_CHECK_INTERVAL_MS)) {
|| (m_lastIPCheckTime.secsTo(QDateTime::currentDateTime()) * 1000 > IP_CHECK_INTERVAL_MS))
{
checkPublicIP();
}
}
@@ -82,30 +83,36 @@ void DNSUpdater::checkPublicIP()
void DNSUpdater::ipRequestFinished(const DownloadResult &result)
{
if (result.status != DownloadStatus::Success) {
if (result.status != DownloadStatus::Success)
{
qWarning() << "IP request failed:" << result.errorString;
return;
}
// Parse response
const QRegularExpressionMatch ipRegexMatch = QRegularExpression("Current IP Address:\\s+([^<]+)</body>").match(result.data);
if (ipRegexMatch.hasMatch()) {
if (ipRegexMatch.hasMatch())
{
QString ipStr = ipRegexMatch.captured(1);
qDebug() << Q_FUNC_INFO << "Regular expression captured the following IP:" << ipStr;
QHostAddress newIp(ipStr);
if (!newIp.isNull()) {
if (m_lastIP != newIp) {
if (!newIp.isNull())
{
if (m_lastIP != newIp)
{
qDebug() << Q_FUNC_INFO << "The IP address changed, report the change to DynDNS...";
qDebug() << m_lastIP.toString() << "->" << newIp.toString();
m_lastIP = newIp;
updateDNSService();
}
}
else {
else
{
qWarning() << Q_FUNC_INFO << "Failed to construct a QHostAddress from the IP string";
}
}
else {
else
{
qWarning() << Q_FUNC_INFO << "Regular expression failed to capture the IP address";
}
}
@@ -133,7 +140,8 @@ QString DNSUpdater::getUpdateUrl() const
Q_ASSERT(!m_lastIP.isNull());
// Service specific
switch (m_service) {
switch (m_service)
{
case DNS::DYNDNS:
url.setHost("members.dyndns.org");
break;
@@ -171,12 +179,14 @@ void DNSUpdater::processIPUpdateReply(const QString &reply)
const QString code = reply.split(' ').first();
qDebug() << Q_FUNC_INFO << "Code:" << code;
if ((code == "good") || (code == "nochg")) {
if ((code == "good") || (code == "nochg"))
{
logger->addMessage(tr("Your dynamic DNS was successfully updated."), Log::INFO);
return;
}
if ((code == "911") || (code == "dnserr")) {
if ((code == "911") || (code == "dnserr"))
{
logger->addMessage(tr("Dynamic DNS error: The service is temporarily unavailable, it will be retried in 30 minutes."), Log::CRITICAL);
m_lastIP.clear();
// It will retry in 30 minutes because the timer was not stopped
@@ -186,33 +196,38 @@ void DNSUpdater::processIPUpdateReply(const QString &reply)
// Everything below is an error, stop updating until the user updates something
m_ipCheckTimer.stop();
m_lastIP.clear();
if (code == "nohost") {
if (code == "nohost")
{
logger->addMessage(tr("Dynamic DNS error: hostname supplied does not exist under specified account."), Log::CRITICAL);
m_state = INVALID_CREDS;
return;
}
if (code == "badauth") {
if (code == "badauth")
{
logger->addMessage(tr("Dynamic DNS error: Invalid username/password."), Log::CRITICAL);
m_state = INVALID_CREDS;
return;
}
if (code == "badagent") {
if (code == "badagent")
{
logger->addMessage(tr("Dynamic DNS error: qBittorrent was blacklisted by the service, please report a bug at http://bugs.qbittorrent.org."),
Log::CRITICAL);
m_state = FATAL;
return;
}
if (code == "!donator") {
if (code == "!donator")
{
logger->addMessage(tr("Dynamic DNS error: %1 was returned by the service, please report a bug at http://bugs.qbittorrent.org.").arg("!donator"),
Log::CRITICAL);
m_state = FATAL;
return;
}
if (code == "abuse") {
if (code == "abuse")
{
logger->addMessage(tr("Dynamic DNS error: Your username was blocked due to abuse."), Log::CRITICAL);
m_state = FATAL;
}
@@ -225,14 +240,17 @@ void DNSUpdater::updateCredentials()
Logger *const logger = Logger::instance();
bool change = false;
// Get DNS service information
if (m_service != pref->getDynDNSService()) {
if (m_service != pref->getDynDNSService())
{
m_service = pref->getDynDNSService();
change = true;
}
if (m_domain != pref->getDynDomainName()) {
if (m_domain != pref->getDynDomainName())
{
m_domain = pref->getDynDomainName();
const QRegularExpressionMatch domainRegexMatch = QRegularExpression("^(?:(?!\\d|-)[a-zA-Z0-9\\-]{1,63}\\.)+[a-zA-Z]{2,}$").match(m_domain);
if (!domainRegexMatch.hasMatch()) {
if (!domainRegexMatch.hasMatch())
{
logger->addMessage(tr("Dynamic DNS error: supplied domain name is invalid."), Log::CRITICAL);
m_lastIP.clear();
m_ipCheckTimer.stop();
@@ -241,9 +259,11 @@ void DNSUpdater::updateCredentials()
}
change = true;
}
if (m_username != pref->getDynDNSUsername()) {
if (m_username != pref->getDynDNSUsername())
{
m_username = pref->getDynDNSUsername();
if (m_username.length() < 4) {
if (m_username.length() < 4)
{
logger->addMessage(tr("Dynamic DNS error: supplied username is too short."), Log::CRITICAL);
m_lastIP.clear();
m_ipCheckTimer.stop();
@@ -252,9 +272,11 @@ void DNSUpdater::updateCredentials()
}
change = true;
}
if (m_password != pref->getDynDNSPassword()) {
if (m_password != pref->getDynDNSPassword())
{
m_password = pref->getDynDNSPassword();
if (m_password.length() < 4) {
if (m_password.length() < 4)
{
logger->addMessage(tr("Dynamic DNS error: supplied password is too short."), Log::CRITICAL);
m_lastIP.clear();
m_ipCheckTimer.stop();
@@ -264,7 +286,8 @@ void DNSUpdater::updateCredentials()
change = true;
}
if ((m_state == INVALID_CREDS) && change) {
if ((m_state == INVALID_CREDS) && change)
{
m_state = OK; // Try again
m_ipCheckTimer.start();
checkPublicIP();
@@ -273,7 +296,8 @@ void DNSUpdater::updateCredentials()
QUrl DNSUpdater::getRegistrationUrl(const int service)
{
switch (service) {
switch (service)
{
case DNS::DYNDNS:
return {"https://www.dyndns.com/account/services/hosts/add.html"};
case DNS::NOIP:

View File

@@ -66,10 +66,12 @@ DownloadHandlerImpl::DownloadHandlerImpl(Net::DownloadManager *manager, const Ne
void DownloadHandlerImpl::cancel()
{
if (m_reply) {
if (m_reply)
{
m_reply->abort();
}
else {
else
{
setError(errorCodeToString(QNetworkReply::OperationCanceledError));
finish();
}
@@ -103,7 +105,8 @@ void DownloadHandlerImpl::processFinishedDownload()
qDebug("Download finished: %s", qUtf8Printable(url()));
// Check if the request was successful
if (m_reply->error() != QNetworkReply::NoError) {
if (m_reply->error() != QNetworkReply::NoError)
{
// Failure
qDebug("Download failure (%s), reason: %s", qUtf8Printable(url()), qUtf8Printable(errorCodeToString(m_reply->error())));
setError(errorCodeToString(m_reply->error()));
@@ -113,7 +116,8 @@ void DownloadHandlerImpl::processFinishedDownload()
// Check if the server ask us to redirect somewhere else
const QVariant redirection = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (redirection.isValid()) {
if (redirection.isValid())
{
handleRedirection(redirection.toUrl());
return;
}
@@ -123,7 +127,8 @@ void DownloadHandlerImpl::processFinishedDownload()
? Utils::Gzip::decompress(m_reply->readAll())
: m_reply->readAll();
if (m_downloadRequest.saveToFile()) {
if (m_downloadRequest.saveToFile())
{
QString filePath;
if (saveToFile(m_result.data, filePath))
m_result.filePath = filePath;
@@ -136,13 +141,15 @@ void DownloadHandlerImpl::processFinishedDownload()
void DownloadHandlerImpl::checkDownloadSize(const qint64 bytesReceived, const qint64 bytesTotal)
{
if ((bytesTotal > 0) && (bytesTotal <= m_downloadRequest.limit())) {
if ((bytesTotal > 0) && (bytesTotal <= m_downloadRequest.limit()))
{
// Total number of bytes is available
disconnect(m_reply, &QNetworkReply::downloadProgress, this, &DownloadHandlerImpl::checkDownloadSize);
return;
}
if ((bytesTotal > m_downloadRequest.limit()) || (bytesReceived > m_downloadRequest.limit())) {
if ((bytesTotal > m_downloadRequest.limit()) || (bytesReceived > m_downloadRequest.limit()))
{
m_reply->abort();
setError(tr("The file size (%1) exceeds the download limit (%2)")
.arg(Utils::Misc::friendlyUnit(bytesTotal)
@@ -153,7 +160,8 @@ void DownloadHandlerImpl::checkDownloadSize(const qint64 bytesReceived, const qi
void DownloadHandlerImpl::handleRedirection(const QUrl &newUrl)
{
if (m_redirectionCount >= MAX_REDIRECTIONS) {
if (m_redirectionCount >= MAX_REDIRECTIONS)
{
setError(tr("Exceeded max redirections (%1)").arg(MAX_REDIRECTIONS));
finish();
return;
@@ -165,7 +173,8 @@ void DownloadHandlerImpl::handleRedirection(const QUrl &newUrl)
qDebug("Redirecting from %s to %s...", qUtf8Printable(m_reply->url().toString()), qUtf8Printable(newUrlString));
// Redirect to magnet workaround
if (newUrlString.startsWith("magnet:", Qt::CaseInsensitive)) {
if (newUrlString.startsWith("magnet:", Qt::CaseInsensitive))
{
qDebug("Magnet redirect detected.");
m_result.status = Net::DownloadStatus::RedirectedToMagnet;
m_result.magnet = newUrlString;
@@ -199,7 +208,8 @@ void DownloadHandlerImpl::finish()
QString DownloadHandlerImpl::errorCodeToString(const QNetworkReply::NetworkError status)
{
switch (status) {
switch (status)
{
case QNetworkReply::HostNotFoundError:
return tr("The remote host name was not found (invalid hostname)");
case QNetworkReply::OperationCanceledError:

View File

@@ -60,7 +60,8 @@ namespace
{
const QDateTime now = QDateTime::currentDateTime();
QList<QNetworkCookie> cookies = Preferences::instance()->getNetworkCookies();
for (const QNetworkCookie &cookie : asConst(Preferences::instance()->getNetworkCookies())) {
for (const QNetworkCookie &cookie : asConst(Preferences::instance()->getNetworkCookies()))
{
if (cookie.isSessionCookie() || (cookie.expirationDate() <= now))
cookies.removeAll(cookie);
}
@@ -72,7 +73,8 @@ namespace
{
const QDateTime now = QDateTime::currentDateTime();
QList<QNetworkCookie> cookies = allCookies();
for (const QNetworkCookie &cookie : asConst(allCookies())) {
for (const QNetworkCookie &cookie : asConst(allCookies()))
{
if (cookie.isSessionCookie() || (cookie.expirationDate() <= now))
cookies.removeAll(cookie);
}
@@ -87,7 +89,8 @@ namespace
{
const QDateTime now = QDateTime::currentDateTime();
QList<QNetworkCookie> cookies = QNetworkCookieJar::cookiesForUrl(url);
for (const QNetworkCookie &cookie : asConst(QNetworkCookieJar::cookiesForUrl(url))) {
for (const QNetworkCookie &cookie : asConst(QNetworkCookieJar::cookiesForUrl(url)))
{
if (!cookie.isSessionCookie() && (cookie.expirationDate() <= now))
cookies.removeAll(cookie);
}
@@ -99,7 +102,8 @@ namespace
{
const QDateTime now = QDateTime::currentDateTime();
QList<QNetworkCookie> cookies = cookieList;
for (const QNetworkCookie &cookie : cookieList) {
for (const QNetworkCookie &cookie : cookieList)
{
if (!cookie.isSessionCookie() && (cookie.expirationDate() <= now))
cookies.removeAll(cookie);
}
@@ -172,10 +176,12 @@ Net::DownloadHandler *Net::DownloadManager::download(const DownloadRequest &down
m_waitingJobs[id].removeOne(downloadHandler);
});
if (isSequentialService && m_busyServices.contains(id)) {
if (isSequentialService && m_busyServices.contains(id))
{
m_waitingJobs[id].enqueue(downloadHandler);
}
else {
else
{
qDebug("Downloading %s...", qUtf8Printable(downloadRequest.url()));
if (isSequentialService)
m_busyServices.insert(id);
@@ -230,27 +236,32 @@ void Net::DownloadManager::applyProxySettings()
const ProxyConfiguration proxyConfig = proxyManager->proxyConfiguration();
QNetworkProxy proxy;
if (!proxyManager->isProxyOnlyForTorrents() && (proxyConfig.type != ProxyType::None)) {
if (!proxyManager->isProxyOnlyForTorrents() && (proxyConfig.type != ProxyType::None))
{
// Proxy enabled
proxy.setHostName(proxyConfig.ip);
proxy.setPort(proxyConfig.port);
// Default proxy type is HTTP, we must change if it is SOCKS5
if ((proxyConfig.type == ProxyType::SOCKS5) || (proxyConfig.type == ProxyType::SOCKS5_PW)) {
if ((proxyConfig.type == ProxyType::SOCKS5) || (proxyConfig.type == ProxyType::SOCKS5_PW))
{
qDebug() << Q_FUNC_INFO << "using SOCKS proxy";
proxy.setType(QNetworkProxy::Socks5Proxy);
}
else {
else
{
qDebug() << Q_FUNC_INFO << "using HTTP proxy";
proxy.setType(QNetworkProxy::HttpProxy);
}
// Authentication?
if (proxyManager->isAuthenticationRequired()) {
if (proxyManager->isAuthenticationRequired())
{
qDebug("Proxy requires authentication, authenticating...");
proxy.setUser(proxyConfig.username);
proxy.setPassword(proxyConfig.password);
}
}
else {
else
{
proxy.setType(QNetworkProxy::NoProxy);
}
@@ -264,7 +275,8 @@ void Net::DownloadManager::handleReplyFinished(const QNetworkReply *reply)
// in the case when the redirection occurred.
const ServiceID id = ServiceID::fromURL(reply->request().url());
const auto waitingJobsIter = m_waitingJobs.find(id);
if ((waitingJobsIter == m_waitingJobs.end()) || waitingJobsIter.value().isEmpty()) {
if ((waitingJobsIter == m_waitingJobs.end()) || waitingJobsIter.value().isEmpty())
{
// No more waiting jobs for given ServiceID
m_busyServices.remove(id);
return;

View File

@@ -88,26 +88,30 @@ GeoIPDatabase *GeoIPDatabase::load(const QString &filename, QString &error)
{
GeoIPDatabase *db = nullptr;
QFile file(filename);
if (file.size() > MAX_FILE_SIZE) {
if (file.size() > MAX_FILE_SIZE)
{
error = tr("Unsupported database file size.");
return nullptr;
}
if (!file.open(QFile::ReadOnly)) {
if (!file.open(QFile::ReadOnly))
{
error = file.errorString();
return nullptr;
}
db = new GeoIPDatabase(file.size());
if (file.read(reinterpret_cast<char *>(db->m_data), db->m_size) != db->m_size) {
if (file.read(reinterpret_cast<char *>(db->m_data), db->m_size) != db->m_size)
{
error = file.errorString();
delete db;
return nullptr;
}
if (!db->parseMetadata(db->readMetadata(), error) || !db->loadDB(error)) {
if (!db->parseMetadata(db->readMetadata(), error) || !db->loadDB(error))
{
delete db;
return nullptr;
}
@@ -118,7 +122,8 @@ GeoIPDatabase *GeoIPDatabase::load(const QString &filename, QString &error)
GeoIPDatabase *GeoIPDatabase::load(const QByteArray &data, QString &error)
{
GeoIPDatabase *db = nullptr;
if (data.size() > MAX_FILE_SIZE) {
if (data.size() > MAX_FILE_SIZE)
{
error = tr("Unsupported database file size.");
return nullptr;
}
@@ -127,7 +132,8 @@ GeoIPDatabase *GeoIPDatabase::load(const QByteArray &data, QString &error)
memcpy(reinterpret_cast<char *>(db->m_data), data.constData(), db->m_size);
if (!db->parseMetadata(db->readMetadata(), error) || !db->loadDB(error)) {
if (!db->parseMetadata(db->readMetadata(), error) || !db->loadDB(error))
{
delete db;
return nullptr;
}
@@ -161,8 +167,10 @@ QString GeoIPDatabase::lookup(const QHostAddress &hostAddr) const
const uchar *ptr = m_data;
for (int i = 0; i < 16; ++i) {
for (int j = 0; j < 8; ++j) {
for (int i = 0; i < 16; ++i)
{
for (int j = 0; j < 8; ++j)
{
const bool right = static_cast<bool>((addr[i] >> (7 - j)) & 1);
// Interpret the left/right record as number
if (right)
@@ -173,16 +181,20 @@ QString GeoIPDatabase::lookup(const QHostAddress &hostAddr) const
memcpy(&idPtr[4 - m_recordBytes], ptr, m_recordBytes);
fromBigEndian(idPtr, 4);
if (id == m_nodeCount) {
if (id == m_nodeCount)
{
return {};
}
if (id > m_nodeCount) {
if (id > m_nodeCount)
{
QString country = m_countries.value(id);
if (country.isEmpty()) {
if (country.isEmpty())
{
const quint32 offset = id - m_nodeCount - sizeof(DATA_SECTION_SEPARATOR);
quint32 tmp = offset + m_indexSize + sizeof(DATA_SECTION_SEPARATOR);
const QVariant val = readDataField(tmp);
if (val.userType() == QMetaType::QVariantHash) {
if (val.userType() == QMetaType::QVariantHash)
{
country = val.toHash()["country"].toHash()["iso_code"].toString();
m_countries[id] = country;
}
@@ -198,18 +210,22 @@ QString GeoIPDatabase::lookup(const QHostAddress &hostAddr) const
}
#define CHECK_METADATA_REQ(key, type) \
if (!metadata.contains(#key)) { \
if (!metadata.contains(#key)) \
{ \
error = errMsgNotFound.arg(#key); \
return false; \
} \
if (metadata.value(#key).userType() != QMetaType::type) { \
if (metadata.value(#key).userType() != QMetaType::type) \
{ \
error = errMsgInvalid.arg(#key); \
return false; \
}
#define CHECK_METADATA_OPT(key, type) \
if (metadata.contains(#key)) { \
if (metadata.value(#key).userType() != QMetaType::type) { \
if (metadata.contains(#key)) \
{ \
if (metadata.value(#key).userType() != QMetaType::type) \
{ \
error = errMsgInvalid.arg(#key); \
return false; \
} \
@@ -226,21 +242,24 @@ bool GeoIPDatabase::parseMetadata(const QVariantHash &metadata, QString &error)
CHECK_METADATA_REQ(binary_format_minor_version, UShort);
const uint versionMajor = metadata.value("binary_format_major_version").toUInt();
const uint versionMinor = metadata.value("binary_format_minor_version").toUInt();
if (versionMajor != 2) {
if (versionMajor != 2)
{
error = tr("Unsupported database version: %1.%2").arg(versionMajor).arg(versionMinor);
return false;
}
CHECK_METADATA_REQ(ip_version, UShort);
m_ipVersion = metadata.value("ip_version").value<quint16>();
if (m_ipVersion != 6) {
if (m_ipVersion != 6)
{
error = tr("Unsupported IP version: %1").arg(m_ipVersion);
return false;
}
CHECK_METADATA_REQ(record_size, UShort);
m_recordSize = metadata.value("record_size").value<quint16>();
if (m_recordSize != 24) {
if (m_recordSize != 24)
{
error = tr("Unsupported record size: %1").arg(m_recordSize);
return false;
}
@@ -270,7 +289,8 @@ bool GeoIPDatabase::loadDB(QString &error) const
const int nodeSize = m_recordSize / 4; // in bytes
const int indexSize = m_nodeCount * nodeSize;
if ((m_size < (indexSize + sizeof(DATA_SECTION_SEPARATOR)))
|| (memcmp(m_data + indexSize, DATA_SECTION_SEPARATOR, sizeof(DATA_SECTION_SEPARATOR)) != 0)) {
|| (memcmp(m_data + indexSize, DATA_SECTION_SEPARATOR, sizeof(DATA_SECTION_SEPARATOR)) != 0))
{
error = tr("Database corrupted: no data section found.");
return false;
}
@@ -282,14 +302,16 @@ QVariantHash GeoIPDatabase::readMetadata() const
{
const char *ptr = reinterpret_cast<const char *>(m_data);
quint32 size = m_size;
if (m_size > MAX_METADATA_SIZE) {
if (m_size > MAX_METADATA_SIZE)
{
ptr += m_size - MAX_METADATA_SIZE;
size = MAX_METADATA_SIZE;
}
const QByteArray data = QByteArray::fromRawData(ptr, size);
int index = data.lastIndexOf(METADATA_BEGIN_MARK);
if (index >= 0) {
if (index >= 0)
{
if (m_size > MAX_METADATA_SIZE)
index += (m_size - MAX_METADATA_SIZE); // from begin of all data
auto offset = static_cast<quint32>(index + strlen(METADATA_BEGIN_MARK));
@@ -309,7 +331,8 @@ QVariant GeoIPDatabase::readDataField(quint32 &offset) const
quint32 locOffset = offset;
bool usePointer = false;
if (descr.fieldType == DataType::Pointer) {
if (descr.fieldType == DataType::Pointer)
{
usePointer = true;
// convert offset from data section to global
locOffset = descr.offset + (m_nodeCount * m_recordSize / 4) + sizeof(DATA_SECTION_SEPARATOR);
@@ -318,7 +341,8 @@ QVariant GeoIPDatabase::readDataField(quint32 &offset) const
}
QVariant fieldValue;
switch (descr.fieldType) {
switch (descr.fieldType)
{
case DataType::Pointer:
qDebug() << "* Illegal Pointer using";
break;
@@ -388,7 +412,8 @@ bool GeoIPDatabase::readDataFieldDescriptor(quint32 &offset, DataFieldDescriptor
if (availSize < 1) return false;
out.fieldType = static_cast<DataType>((dataPtr[0] & 0xE0) >> 5);
if (out.fieldType == DataType::Pointer) {
if (out.fieldType == DataType::Pointer)
{
const int size = ((dataPtr[0] & 0x18) >> 3);
if (availSize < (size + 2)) return false;
@@ -406,28 +431,34 @@ bool GeoIPDatabase::readDataFieldDescriptor(quint32 &offset, DataFieldDescriptor
}
out.fieldSize = dataPtr[0] & 0x1F;
if (out.fieldSize <= 28) {
if (out.fieldType == DataType::Unknown) {
if (out.fieldSize <= 28)
{
if (out.fieldType == DataType::Unknown)
{
out.fieldType = static_cast<DataType>(dataPtr[1] + 7);
if ((out.fieldType <= DataType::Map) || (out.fieldType > DataType::Float) || (availSize < 3))
return false;
offset += 2;
}
else {
else
{
offset += 1;
}
}
else if (out.fieldSize == 29) {
else if (out.fieldSize == 29)
{
if (availSize < 2) return false;
out.fieldSize = dataPtr[1] + 29;
offset += 2;
}
else if (out.fieldSize == 30) {
else if (out.fieldSize == 30)
{
if (availSize < 3) return false;
out.fieldSize = (dataPtr[1] << 8) + dataPtr[2] + 285;
offset += 3;
}
else if (out.fieldSize == 31) {
else if (out.fieldSize == 31)
{
if (availSize < 4) return false;
out.fieldSize = (dataPtr[1] << 16) + (dataPtr[2] << 8) + dataPtr[3] + 65821;
offset += 4;
@@ -450,7 +481,8 @@ QVariant GeoIPDatabase::readMapValue(quint32 &offset, const quint32 count) const
{
QVariantHash map;
for (quint32 i = 0; i < count; ++i) {
for (quint32 i = 0; i < count; ++i)
{
QVariant field = readDataField(offset);
if (field.userType() != QMetaType::QString)
return {};
@@ -470,7 +502,8 @@ QVariant GeoIPDatabase::readArrayValue(quint32 &offset, const quint32 count) con
{
QVariantList array;
for (quint32 i = 0; i < count; ++i) {
for (quint32 i = 0; i < count; ++i)
{
const QVariant field = readDataField(offset);
if (field.userType() == QVariant::Invalid)
return {};

View File

@@ -74,7 +74,8 @@ private:
const uchar *const data = m_data + offset;
const quint32 availSize = m_size - offset;
if ((len > 0) && (len <= sizeof(T) && (availSize >= len))) {
if ((len > 0) && (len <= sizeof(T) && (availSize >= len)))
{
// copy input data to last 'len' bytes of 'value'
uchar *dst = reinterpret_cast<uchar *>(&value) + (sizeof(T) - len);
memcpy(dst, data, len);

View File

@@ -140,7 +140,8 @@ QString GeoIPManager::lookup(const QHostAddress &hostAddr) const
QString GeoIPManager::CountryName(const QString &countryISOCode)
{
static const QHash<QString, QString> countries = {
static const QHash<QString, QString> countries =
{
// ISO 3166-1 alpha-2 codes
// http://www.iso.org/iso/home/standards/country_codes/country_names_and_code_elements_txt-temp.htm
@@ -404,12 +405,15 @@ QString GeoIPManager::CountryName(const QString &countryISOCode)
void GeoIPManager::configure()
{
const bool enabled = Preferences::instance()->resolvePeerCountries();
if (m_enabled != enabled) {
if (m_enabled != enabled)
{
m_enabled = enabled;
if (m_enabled && !m_geoIPDatabase) {
if (m_enabled && !m_geoIPDatabase)
{
loadDatabase();
}
else if (!m_enabled) {
else if (!m_enabled)
{
delete m_geoIPDatabase;
m_geoIPDatabase = nullptr;
}
@@ -418,22 +422,26 @@ void GeoIPManager::configure()
void GeoIPManager::downloadFinished(const DownloadResult &result)
{
if (result.status != DownloadStatus::Success) {
if (result.status != DownloadStatus::Success)
{
LogMsg(tr("Couldn't download IP geolocation database file. Reason: %1").arg(result.errorString), Log::WARNING);
return;
}
bool ok = false;
const QByteArray data = Utils::Gzip::decompress(result.data, &ok);
if (!ok) {
if (!ok)
{
LogMsg(tr("Could not decompress IP geolocation database file."), Log::WARNING);
return;
}
QString error;
GeoIPDatabase *geoIPDatabase = GeoIPDatabase::load(data, error);
if (geoIPDatabase) {
if (!m_geoIPDatabase || (geoIPDatabase->buildEpoch() > m_geoIPDatabase->buildEpoch())) {
if (geoIPDatabase)
{
if (!m_geoIPDatabase || (geoIPDatabase->buildEpoch() > m_geoIPDatabase->buildEpoch()))
{
delete m_geoIPDatabase;
m_geoIPDatabase = geoIPDatabase;
LogMsg(tr("IP geolocation database loaded. Type: %1. Build time: %2.")
@@ -449,11 +457,13 @@ void GeoIPManager::downloadFinished(const DownloadResult &result)
else
LogMsg(tr("Successfully updated IP geolocation database."), Log::INFO);
}
else {
else
{
delete geoIPDatabase;
}
}
else {
else
{
LogMsg(tr("Couldn't load IP geolocation database. Reason: %1").arg(error), Log::WARNING);
}
}

View File

@@ -100,7 +100,8 @@ ProxyConfiguration ProxyConfigurationManager::proxyConfiguration() const
void ProxyConfigurationManager::setProxyConfiguration(const ProxyConfiguration &config)
{
if (config != m_config) {
if (config != m_config)
{
m_config = config;
settings()->storeValue(KEY_TYPE, static_cast<int>(config.type));
settings()->storeValue(KEY_IP, config.ip);
@@ -120,7 +121,8 @@ bool ProxyConfigurationManager::isProxyOnlyForTorrents() const
void ProxyConfigurationManager::setProxyOnlyForTorrents(bool onlyForTorrents)
{
if (m_isProxyOnlyForTorrents != onlyForTorrents) {
if (m_isProxyOnlyForTorrents != onlyForTorrents)
{
settings()->storeValue(KEY_ONLY_FOR_TORRENTS, onlyForTorrents);
m_isProxyOnlyForTorrents = onlyForTorrents;
}
@@ -136,8 +138,10 @@ void ProxyConfigurationManager::configureProxy()
{
// Define environment variables for urllib in search engine plugins
QString proxyStrHTTP, proxyStrSOCK;
if (!m_isProxyOnlyForTorrents) {
switch (m_config.type) {
if (!m_isProxyOnlyForTorrents)
{
switch (m_config.type)
{
case ProxyType::HTTP_PW:
proxyStrHTTP = QString::fromLatin1("http://%1:%2@%3:%4").arg(m_config.username
, m_config.password, m_config.ip, QString::number(m_config.port));

View File

@@ -60,7 +60,8 @@ ReverseResolution::~ReverseResolution()
void ReverseResolution::resolve(const QHostAddress &ip)
{
const QString *hostname = m_cache.object(ip);
if (hostname) {
if (hostname)
{
emit ipResolved(ip, *hostname);
return;
}
@@ -74,7 +75,8 @@ void ReverseResolution::hostResolved(const QHostInfo &host)
{
const QHostAddress ip = m_lookups.take(host.lookupId());
if (host.error() != QHostInfo::NoError) {
if (host.error() != QHostInfo::NoError)
{
emit ipResolved(ip, {});
return;
}

View File

@@ -67,7 +67,8 @@ namespace
// ascii characters 0x36 ("6") and 0x5c ("\") are selected because they have large
// Hamming distance (http://en.wikipedia.org/wiki/Hamming_distance)
for (int i = 0; i < key.length(); ++i) {
for (int i = 0; i < key.length(); ++i)
{
innerPadding[i] = innerPadding[i] ^ key.at(i); // XOR operation between every byte in key and innerpadding, of key length
outerPadding[i] = outerPadding[i] ^ key.at(i); // XOR operation between every byte in key and outerpadding, of key length
}
@@ -100,7 +101,8 @@ Smtp::Smtp(QObject *parent)
{
static bool needToRegisterMetaType = true;
if (needToRegisterMetaType) {
if (needToRegisterMetaType)
{
qRegisterMetaType<QAbstractSocket::SocketError>();
needToRegisterMetaType = false;
}
@@ -153,18 +155,21 @@ void Smtp::sendMail(const QString &from, const QString &to, const QString &subje
m_from = from;
m_rcpt = to;
// Authentication
if (pref->getMailNotificationSMTPAuth()) {
if (pref->getMailNotificationSMTPAuth())
{
m_username = pref->getMailNotificationSMTPUsername();
m_password = pref->getMailNotificationSMTPPassword();
}
// Connect to SMTP server
#ifndef QT_NO_OPENSSL
if (pref->getMailNotificationSMTPSSL()) {
if (pref->getMailNotificationSMTPSSL())
{
m_socket->connectToHostEncrypted(pref->getMailNotificationSMTP(), DEFAULT_PORT_SSL);
m_useSsl = true;
}
else {
else
{
#endif
m_socket->connectToHost(pref->getMailNotificationSMTP(), DEFAULT_PORT);
m_useSsl = false;
@@ -178,7 +183,8 @@ void Smtp::readyRead()
qDebug() << Q_FUNC_INFO;
// SMTP is line-oriented
m_buffer += m_socket->readAll();
while (true) {
while (true)
{
const int pos = m_buffer.indexOf("\r\n");
if (pos < 0) return; // Loop exit condition
const QByteArray line = m_buffer.left(pos);
@@ -187,9 +193,11 @@ void Smtp::readyRead()
// Extract response code
const QByteArray code = line.left(3);
switch (m_state) {
switch (m_state)
{
case Init:
if (code[0] == '2') {
if (code[0] == '2')
{
// The server may send a multiline greeting/INIT/220 response.
// We wait until it finishes.
if (line[3] != ' ')
@@ -197,7 +205,8 @@ void Smtp::readyRead()
// Connection was successful
ehlo();
}
else {
else
{
logError(QLatin1String("Connection failed, unrecognized reply: ") + line);
m_state = Close;
}
@@ -209,11 +218,13 @@ void Smtp::readyRead()
break;
#ifndef QT_NO_OPENSSL
case StartTLSSent:
if (code == "220") {
if (code == "220")
{
m_socket->startClientEncryption();
ehlo();
}
else {
else
{
authenticate();
}
break;
@@ -226,59 +237,69 @@ void Smtp::readyRead()
break;
case AuthSent:
case Authenticated:
if (code[0] == '2') {
if (code[0] == '2')
{
qDebug() << "Sending <mail from>...";
m_socket->write("mail from:<" + m_from.toLatin1() + ">\r\n");
m_socket->flush();
m_state = Rcpt;
}
else {
else
{
// Authentication failed!
logError(QLatin1String("Authentication failed, msg: ") + line);
m_state = Close;
}
break;
case Rcpt:
if (code[0] == '2') {
if (code[0] == '2')
{
m_socket->write("rcpt to:<" + m_rcpt.toLatin1() + ">\r\n");
m_socket->flush();
m_state = Data;
}
else {
else
{
logError(QLatin1String("<mail from> was rejected by server, msg: ") + line);
m_state = Close;
}
break;
case Data:
if (code[0] == '2') {
if (code[0] == '2')
{
m_socket->write("data\r\n");
m_socket->flush();
m_state = Body;
}
else {
else
{
logError(QLatin1String("<Rcpt to> was rejected by server, msg: ") + line);
m_state = Close;
}
break;
case Body:
if (code[0] == '3') {
if (code[0] == '3')
{
m_socket->write(m_message + "\r\n.\r\n");
m_socket->flush();
m_state = Quit;
}
else {
else
{
logError(QLatin1String("<data> was rejected by server, msg: ") + line);
m_state = Close;
}
break;
case Quit:
if (code[0] == '2') {
if (code[0] == '2')
{
m_socket->write("QUIT\r\n");
m_socket->flush();
// here, we just close.
m_state = Close;
}
else {
else
{
logError(QLatin1String("Message was rejected by the server, error: ") + line);
m_state = Close;
}
@@ -296,10 +317,13 @@ QByteArray Smtp::encodeMimeHeader(const QString &key, const QString &value, cons
QByteArray rv = "";
QByteArray line = key.toLatin1() + ": ";
if (!prefix.isEmpty()) line += prefix;
if (!value.contains("=?") && latin1->canEncode(value)) {
if (!value.contains("=?") && latin1->canEncode(value))
{
bool firstWord = true;
for (const QByteArray &word : asConst(value.toLatin1().split(' '))) {
if (line.size() > 78) {
for (const QByteArray &word : asConst(value.toLatin1().split(' ')))
{
if (line.size() > 78)
{
rv = rv + line + "\r\n";
line.clear();
}
@@ -310,7 +334,8 @@ QByteArray Smtp::encodeMimeHeader(const QString &key, const QString &value, cons
firstWord = false;
}
}
else {
else
{
// The text cannot be losslessly encoded as Latin-1. Therefore, we
// must use base64 encoding.
const QByteArray utf8 = value.toUtf8();
@@ -318,8 +343,10 @@ QByteArray Smtp::encodeMimeHeader(const QString &key, const QString &value, cons
const QByteArray base64 = utf8.toBase64();
const int ct = base64.length();
line += "=?utf-8?b?";
for (int i = 0; i < ct; i += 4) {
/*if (line.length() > 72) {
for (int i = 0; i < ct; i += 4)
{
/*if (line.length() > 72)
{
rv += line + "?\n\r";
line = " =?utf-8?b?";
}*/
@@ -348,14 +375,17 @@ void Smtp::helo()
void Smtp::parseEhloResponse(const QByteArray &code, const bool continued, const QString &line)
{
if (code != "250") {
if (code != "250")
{
// Error
if (m_state == EhloSent) {
if (m_state == EhloSent)
{
// try to send HELO instead of EHLO
qDebug() << "EHLO failed, trying HELO instead...";
helo();
}
else {
else
{
// Both EHLO and HELO failed, chances are this is NOT
// a SMTP server
logError("Both EHLO and HELO failed, msg: " + line);
@@ -364,20 +394,24 @@ void Smtp::parseEhloResponse(const QByteArray &code, const bool continued, const
return;
}
if (m_state != EhloGreetReceived) {
if (!continued) {
if (m_state != EhloGreetReceived)
{
if (!continued)
{
// greeting only, no extensions
qDebug() << "No extension";
m_state = EhloDone;
}
else {
else
{
// greeting followed by extensions
m_state = EhloGreetReceived;
qDebug() << "EHLO greet received";
return;
}
}
else {
else
{
qDebug() << Q_FUNC_INFO << "Supported extension: " << line.section(' ', 0, 0).toUpper()
<< line.section(' ', 1);
m_extensions[line.section(' ', 0, 0).toUpper()] = line.section(' ', 1);
@@ -387,11 +421,13 @@ void Smtp::parseEhloResponse(const QByteArray &code, const bool continued, const
if (m_state != EhloDone) return;
if (m_extensions.contains("STARTTLS") && m_useSsl) {
if (m_extensions.contains("STARTTLS") && m_useSsl)
{
qDebug() << "STARTTLS";
startTLS();
}
else {
else
{
authenticate();
}
}
@@ -400,7 +436,8 @@ void Smtp::authenticate()
{
qDebug() << Q_FUNC_INFO;
if (!m_extensions.contains("AUTH") ||
m_username.isEmpty() || m_password.isEmpty()) {
m_username.isEmpty() || m_password.isEmpty())
{
// Skip authentication
qDebug() << "Skipping authentication...";
m_state = Authenticated;
@@ -414,19 +451,23 @@ void Smtp::authenticate()
// authentication modes are supported by
// the server
const QStringList auth = m_extensions["AUTH"].toUpper().split(' ', QString::SkipEmptyParts);
if (auth.contains("CRAM-MD5")) {
if (auth.contains("CRAM-MD5"))
{
qDebug() << "Using CRAM-MD5 authentication...";
authCramMD5();
}
else if (auth.contains("PLAIN")) {
else if (auth.contains("PLAIN"))
{
qDebug() << "Using PLAIN authentication...";
authPlain();
}
else if (auth.contains("LOGIN")) {
else if (auth.contains("LOGIN"))
{
qDebug() << "Using LOGIN authentication...";
authLogin();
}
else {
else
{
// Skip authentication
logError("The SMTP server does not seem to support any of the authentications modes "
"we support [CRAM-MD5|PLAIN|LOGIN], skipping authentication, "
@@ -453,13 +494,15 @@ void Smtp::startTLS()
void Smtp::authCramMD5(const QByteArray &challenge)
{
if (m_state != AuthRequestSent) {
if (m_state != AuthRequestSent)
{
m_socket->write("auth cram-md5\r\n");
m_socket->flush();
m_authType = AuthCramMD5;
m_state = AuthRequestSent;
}
else {
else
{
const QByteArray response = m_username.toLatin1() + ' '
+ hmacMD5(m_password.toLatin1(), QByteArray::fromBase64(challenge)).toHex();
m_socket->write(response.toBase64() + "\r\n");
@@ -470,7 +513,8 @@ void Smtp::authCramMD5(const QByteArray &challenge)
void Smtp::authPlain()
{
if (m_state != AuthRequestSent) {
if (m_state != AuthRequestSent)
{
m_authType = AuthPlain;
// Prepare Auth string
QByteArray auth;
@@ -489,18 +533,21 @@ void Smtp::authPlain()
void Smtp::authLogin()
{
if ((m_state != AuthRequestSent) && (m_state != AuthUsernameSent)) {
if ((m_state != AuthRequestSent) && (m_state != AuthUsernameSent))
{
m_socket->write("auth login\r\n");
m_socket->flush();
m_authType = AuthLogin;
m_state = AuthRequestSent;
}
else if (m_state == AuthRequestSent) {
else if (m_state == AuthRequestSent)
{
m_socket->write(m_username.toLatin1().toBase64() + "\r\n");
m_socket->flush();
m_state = AuthUsernameSent;
}
else {
else
{
m_socket->write(m_password.toLatin1().toBase64() + "\r\n");
m_socket->flush();
m_state = AuthSent;

View File

@@ -306,11 +306,13 @@ bool Preferences::WinStartup() const
void Preferences::setWinStartup(const bool b)
{
QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
if (b) {
if (b)
{
const QString binPath = '"' + Utils::Fs::toNativePath(qApp->applicationFilePath()) + '"';
settings.setValue("qBittorrent", binPath);
}
else {
else
{
settings.remove("qBittorrent");
}
}
@@ -530,7 +532,8 @@ QVector<Utils::Net::Subnet> Preferences::getWebUiAuthSubnetWhitelist() const
QVector<Utils::Net::Subnet> ret;
ret.reserve(subnets.size());
for (const QString &rawSubnet : subnets) {
for (const QString &rawSubnet : subnets)
{
bool ok = false;
const Utils::Net::Subnet subnet = Utils::Net::parseSubnet(rawSubnet.trimmed(), &ok);
if (ok)
@@ -977,7 +980,8 @@ void Preferences::setNeverCheckFileAssoc(const bool check)
bool Preferences::isTorrentFileAssocSet()
{
const QSettings settings("HKEY_CURRENT_USER\\Software\\Classes", QSettings::NativeFormat);
if (settings.value(".torrent/Default").toString() != "qBittorrent") {
if (settings.value(".torrent/Default").toString() != "qBittorrent")
{
qDebug(".torrent != qBittorrent");
return false;
}
@@ -1008,13 +1012,15 @@ void Preferences::setTorrentFileAssoc(const bool set)
QSettings settings("HKEY_CURRENT_USER\\Software\\Classes", QSettings::NativeFormat);
// .Torrent association
if (set) {
if (set)
{
const QString oldProgId = settings.value(".torrent/Default").toString();
if (!oldProgId.isEmpty() && (oldProgId != "qBittorrent"))
settings.setValue(".torrent/OpenWithProgids/" + oldProgId, "");
settings.setValue(".torrent/Default", "qBittorrent");
}
else if (isTorrentFileAssocSet()) {
else if (isTorrentFileAssocSet())
{
settings.setValue(".torrent/Default", "");
}
@@ -1026,7 +1032,8 @@ void Preferences::setMagnetLinkAssoc(const bool set)
QSettings settings("HKEY_CURRENT_USER\\Software\\Classes", QSettings::NativeFormat);
// Magnet association
if (set) {
if (set)
{
const QString commandStr = '"' + qApp->applicationFilePath() + "\" \"%1\"";
const QString iconStr = '"' + qApp->applicationFilePath() + "\",1";
@@ -1037,7 +1044,8 @@ void Preferences::setMagnetLinkAssoc(const bool set)
settings.setValue("magnet/shell/Default", "open");
settings.setValue("magnet/shell/open/command/Default", Utils::Fs::toNativePath(commandStr));
}
else if (isMagnetLinkAssocSet()) {
else if (isMagnetLinkAssocSet())
{
settings.remove("magnet");
}
@@ -1056,9 +1064,11 @@ bool Preferences::isTorrentFileAssocSet()
{
bool isSet = false;
const CFStringRef torrentId = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, torrentExtension, NULL);
if (torrentId != NULL) {
if (torrentId != NULL)
{
const CFStringRef defaultHandlerId = LSCopyDefaultRoleHandlerForContentType(torrentId, kLSRolesViewer);
if (defaultHandlerId != NULL) {
if (defaultHandlerId != NULL)
{
const CFStringRef myBundleId = CFBundleGetIdentifier(CFBundleGetMainBundle());
isSet = CFStringCompare(myBundleId, defaultHandlerId, 0) == kCFCompareEqualTo;
CFRelease(defaultHandlerId);
@@ -1072,7 +1082,8 @@ bool Preferences::isMagnetLinkAssocSet()
{
bool isSet = false;
const CFStringRef defaultHandlerId = LSCopyDefaultHandlerForURLScheme(magnetUrlScheme);
if (defaultHandlerId != NULL) {
if (defaultHandlerId != NULL)
{
const CFStringRef myBundleId = CFBundleGetIdentifier(CFBundleGetMainBundle());
isSet = CFStringCompare(myBundleId, defaultHandlerId, 0) == kCFCompareEqualTo;
CFRelease(defaultHandlerId);
@@ -1085,7 +1096,8 @@ void Preferences::setTorrentFileAssoc()
if (isTorrentFileAssocSet())
return;
const CFStringRef torrentId = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, torrentExtension, NULL);
if (torrentId != NULL) {
if (torrentId != NULL)
{
const CFStringRef myBundleId = CFBundleGetIdentifier(CFBundleGetMainBundle());
LSSetDefaultRoleHandlerForContentType(torrentId, kLSRolesViewer, myBundleId);
CFRelease(torrentId);

View File

@@ -72,7 +72,8 @@ const Profile *Profile::instance()
QString Profile::location(const SpecialFolder folder) const
{
QString result;
switch (folder) {
switch (folder)
{
case SpecialFolder::Cache:
result = m_profileImpl->cacheLocation();
break;

View File

@@ -83,7 +83,8 @@ QString Private::DefaultProfile::dataLocation() const
const QString dataDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)
+ QLatin1Char('/') + profileName() + QLatin1Char('/');
if (QDir(legacyDir).exists()) {
if (QDir(legacyDir).exists())
{
qWarning("The legacy data directory '%s' is used. It is recommended to move its content to '%s'",
qUtf8Printable(legacyDir), qUtf8Printable(dataDir));
@@ -178,7 +179,8 @@ QString Private::Converter::toPortablePath(const QString &path) const
return path;
#ifdef Q_OS_WIN
if (QDir::isAbsolutePath(path)) {
if (QDir::isAbsolutePath(path))
{
const QChar driveLeter = path[0].toUpper();
const QChar baseDriveLetter = m_baseDir.path()[0].toUpper();
const bool onSameDrive = (driveLeter.category() == QChar::Letter_Uppercase) && (driveLeter == baseDriveLetter);

View File

@@ -126,7 +126,8 @@ QVariantHash Article::data() const
void Article::markAsRead()
{
if (!m_isRead) {
if (!m_isRead)
{
m_isRead = true;
m_data[KeyIsRead] = m_isRead;
emit read(this);

View File

@@ -82,7 +82,8 @@ namespace
const QJsonObject jsonObj {jsonDoc.object()};
QVector<RSS::AutoDownloadRule> rules;
for (auto it = jsonObj.begin(); it != jsonObj.end(); ++it) {
for (auto it = jsonObj.begin(); it != jsonObj.end(); ++it)
{
const QJsonValue jsonVal {it.value()};
if (!jsonVal.isObject())
throw RSS::ParsingError(RSS::AutoDownloader::tr("Invalid data format."));
@@ -177,7 +178,8 @@ QList<AutoDownloadRule> AutoDownloader::rules() const
void AutoDownloader::insertRule(const AutoDownloadRule &rule)
{
if (!hasRule(rule.name())) {
if (!hasRule(rule.name()))
{
// Insert new rule
setRule_impl(rule);
m_dirty = true;
@@ -185,7 +187,8 @@ void AutoDownloader::insertRule(const AutoDownloadRule &rule)
emit ruleAdded(rule.name());
resetProcessingQueue();
}
else if (ruleByName(rule.name()) != rule) {
else if (ruleByName(rule.name()) != rule)
{
// Update existing rule
setRule_impl(rule);
m_dirty = true;
@@ -211,7 +214,8 @@ bool AutoDownloader::renameRule(const QString &ruleName, const QString &newRuleN
void AutoDownloader::removeRule(const QString &ruleName)
{
if (m_rules.contains(ruleName)) {
if (m_rules.contains(ruleName))
{
emit ruleAboutToBeRemoved(ruleName);
m_rules.remove(ruleName);
m_dirty = true;
@@ -221,7 +225,8 @@ void AutoDownloader::removeRule(const QString &ruleName)
QByteArray AutoDownloader::exportRules(AutoDownloader::RulesFileFormat format) const
{
switch (format) {
switch (format)
{
case RulesFileFormat::Legacy:
return exportRulesToLegacyFormat();
default:
@@ -231,7 +236,8 @@ QByteArray AutoDownloader::exportRules(AutoDownloader::RulesFileFormat format) c
void AutoDownloader::importRules(const QByteArray &data, const AutoDownloader::RulesFileFormat format)
{
switch (format) {
switch (format)
{
case RulesFileFormat::Legacy:
importRulesFromLegacyFormat(data);
break;
@@ -286,8 +292,10 @@ QStringList AutoDownloader::smartEpisodeFilters() const
{
const QVariant filtersSetting = SettingsStorage::instance()->loadValue(SettingsKey_SmartEpisodeFilter);
if (filtersSetting.isNull()) {
QStringList filters = {
if (filtersSetting.isNull())
{
QStringList filters =
{
"s(\\d+)e(\\d+)", // Format 1: s01e01
"(\\d+)x(\\d+)", // Format 2: 01x01
"(\\d{4}[.\\-]\\d{1,2}[.\\-]\\d{1,2})", // Format 3: 2017.01.01
@@ -375,7 +383,8 @@ void AutoDownloader::addJobForArticle(const Article *article)
void AutoDownloader::processJob(const QSharedPointer<ProcessingJob> &job)
{
for (AutoDownloadRule &rule : m_rules) {
for (AutoDownloadRule &rule : m_rules)
{
if (!rule.isEnabled()) continue;
if (!rule.feedURLs().contains(job->feedURL)) continue;
if (!rule.accepts(job->articleData)) continue;
@@ -393,13 +402,16 @@ void AutoDownloader::processJob(const QSharedPointer<ProcessingJob> &job)
const auto torrentURL = job->articleData.value(Article::KeyTorrentURL).toString();
BitTorrent::Session::instance()->addTorrent(torrentURL, params);
if (BitTorrent::MagnetUri(torrentURL).isValid()) {
if (Feed *feed = Session::instance()->feedByURL(job->feedURL)) {
if (BitTorrent::MagnetUri(torrentURL).isValid())
{
if (Feed *feed = Session::instance()->feedByURL(job->feedURL))
{
if (Article *article = feed->articleByGUID(job->articleData.value(Article::KeyId).toString()))
article->markAsRead();
}
}
else {
else
{
// waiting for torrent file downloading
m_waitingJobs.insert(torrentURL, job);
}
@@ -423,12 +435,14 @@ void AutoDownloader::load()
void AutoDownloader::loadRules(const QByteArray &data)
{
try {
try
{
const auto rules = rulesFromJSON(data);
for (const auto &rule : rules)
setRule_impl(rule);
}
catch (const ParsingError &error) {
catch (const ParsingError &error)
{
LogMsg(tr("Couldn't load RSS AutoDownloader rules. Reason: %1")
.arg(error.message()), Log::CRITICAL);
}
@@ -438,7 +452,8 @@ void AutoDownloader::loadRulesLegacy()
{
const SettingsPtr settings = Profile::instance()->applicationSettings(QStringLiteral("qBittorrent-rss"));
const QVariantHash rules = settings->value(QStringLiteral("download_rules")).toHash();
for (const QVariant &ruleVar : rules) {
for (const QVariant &ruleVar : rules)
{
const auto rule = AutoDownloadRule::fromLegacyDict(ruleVar.toHash());
if (!rule.name().isEmpty())
insertRule(rule);
@@ -475,7 +490,8 @@ void AutoDownloader::resetProcessingQueue()
m_processingQueue.clear();
if (!m_processingEnabled) return;
for (Article *article : asConst(Session::instance()->rootFolder()->articles())) {
for (Article *article : asConst(Session::instance()->rootFolder()->articles()))
{
if (!article->isRead() && !article->torrentUrl().isEmpty())
addJobForArticle(article);
}
@@ -489,13 +505,16 @@ void AutoDownloader::startProcessing()
void AutoDownloader::setProcessingEnabled(const bool enabled)
{
if (m_processingEnabled != enabled) {
if (m_processingEnabled != enabled)
{
m_processingEnabled = enabled;
SettingsStorage::instance()->storeValue(SettingsKey_ProcessingEnabled, m_processingEnabled);
if (m_processingEnabled) {
if (m_processingEnabled)
{
startProcessing();
}
else {
else
{
m_processingQueue.clear();
disconnect(Session::instance()->rootFolder(), &Folder::newArticle, this, &AutoDownloader::handleNewArticle);
}

View File

@@ -64,7 +64,8 @@ namespace
QJsonValue triStateBoolToJsonValue(const TriStateBool triStateBool)
{
switch (static_cast<signed char>(triStateBool)) {
switch (static_cast<signed char>(triStateBool))
{
case 0: return false;
case 1: return true;
default: return {};
@@ -73,7 +74,8 @@ namespace
TriStateBool addPausedLegacyToTriStateBool(const int val)
{
switch (val) {
switch (val)
{
case 1: return TriStateBool::True; // always
case 2: return TriStateBool::False; // never
default: return TriStateBool::Undefined; // default
@@ -82,7 +84,8 @@ namespace
int triStateBoolToAddPausedLegacy(const TriStateBool triStateBool)
{
switch (static_cast<signed char>(triStateBool)) {
switch (static_cast<signed char>(triStateBool))
{
case 0: return 2; // never
case 1: return 1; // always
default: return 0; // default
@@ -164,7 +167,8 @@ QString computeEpisodeName(const QString &article)
return {};
QStringList ret;
for (int i = 1; i <= match.lastCapturedIndex(); ++i) {
for (int i = 1; i <= match.lastCapturedIndex(); ++i)
{
const QString cap = match.captured(i);
if (cap.isEmpty())
@@ -199,8 +203,10 @@ QRegularExpression AutoDownloadRule::cachedRegex(const QString &expression, cons
Q_ASSERT(!expression.isEmpty());
QRegularExpression &regex = m_dataPtr->cachedRegexes[expression];
if (regex.pattern().isEmpty()) {
regex = QRegularExpression {
if (regex.pattern().isEmpty())
{
regex = QRegularExpression
{
(isRegex ? expression : Utils::String::wildcardToRegex(expression))
, QRegularExpression::CaseInsensitiveOption};
}
@@ -212,12 +218,14 @@ bool AutoDownloadRule::matchesExpression(const QString &articleTitle, const QStr
{
const QRegularExpression whitespace {"\\s+"};
if (expression.isEmpty()) {
if (expression.isEmpty())
{
// A regex of the form "expr|" will always match, so do the same for wildcards
return true;
}
if (m_dataPtr->useRegex) {
if (m_dataPtr->useRegex)
{
const QRegularExpression reg(cachedRegex(expression));
return reg.match(articleTitle).hasMatch();
}
@@ -225,7 +233,8 @@ bool AutoDownloadRule::matchesExpression(const QString &articleTitle, const QStr
// Only match if every wildcard token (separated by spaces) is present in the article name.
// Order of wildcard tokens is unimportant (if order is important, they should have used *).
const QStringList wildcards {expression.split(whitespace, QString::SplitBehavior::SkipEmptyParts)};
for (const QString &wildcard : wildcards) {
for (const QString &wildcard : wildcards)
{
const QRegularExpression reg {cachedRegex(wildcard, false)};
if (!reg.match(articleTitle).hasMatch())
return false;
@@ -279,7 +288,8 @@ bool AutoDownloadRule::matchesEpisodeFilterExpression(const QString &articleTitl
const QStringList episodes {matcher.captured(2).split(';')};
const int seasonOurs {season.toInt()};
for (QString episode : episodes) {
for (QString episode : episodes)
{
if (episode.isEmpty())
continue;
@@ -287,7 +297,8 @@ bool AutoDownloadRule::matchesEpisodeFilterExpression(const QString &articleTitl
while ((episode.size() > 1) && episode.startsWith('0'))
episode = episode.right(episode.size() - 1);
if (episode.indexOf('-') != -1) { // Range detected
if (episode.indexOf('-') != -1)
{ // Range detected
const QString partialPattern1 {"\\bs0?(\\d{1,4})[ -_\\.]?e(0?\\d{1,4})(?:\\D|\\b)"};
const QString partialPattern2 {"\\b(\\d{1,4})x(0?\\d{1,4})(?:\\D|\\b)"};
@@ -295,21 +306,25 @@ bool AutoDownloadRule::matchesEpisodeFilterExpression(const QString &articleTitl
QRegularExpressionMatch matcher = cachedRegex(partialPattern1).match(articleTitle);
bool matched = matcher.hasMatch();
if (!matched) {
if (!matched)
{
matcher = cachedRegex(partialPattern2).match(articleTitle);
matched = matcher.hasMatch();
}
if (matched) {
if (matched)
{
const int seasonTheirs {matcher.captured(1).toInt()};
const int episodeTheirs {matcher.captured(2).toInt()};
if (episode.endsWith('-')) { // Infinite range
if (episode.endsWith('-'))
{ // Infinite range
const int episodeOurs {episode.leftRef(episode.size() - 1).toInt()};
if (((seasonTheirs == seasonOurs) && (episodeTheirs >= episodeOurs)) || (seasonTheirs > seasonOurs))
return true;
}
else { // Normal range
else
{ // Normal range
const QStringList range {episode.split('-')};
Q_ASSERT(range.size() == 2);
if (range.first().toInt() > range.last().toInt())
@@ -322,7 +337,8 @@ bool AutoDownloadRule::matchesEpisodeFilterExpression(const QString &articleTitl
}
}
}
else { // Single number
else
{ // Single number
const QString expStr {QString::fromLatin1("\\b(?:s0?%1[ -_\\.]?e0?%2|%1x0?%2)(?:\\D|\\b)").arg(season, episode)};
if (cachedRegex(expStr).match(articleTitle).hasMatch())
return true;
@@ -343,7 +359,8 @@ bool AutoDownloadRule::matchesSmartEpisodeFilter(const QString &articleTitle) co
// See if this episode has been downloaded before
const bool previouslyMatched = m_dataPtr->previouslyMatchedEpisodes.contains(episodeStr);
if (previouslyMatched) {
if (previouslyMatched)
{
if (!AutoDownloader::instance()->downloadRepacks())
return false;
@@ -365,7 +382,8 @@ bool AutoDownloadRule::matchesSmartEpisodeFilter(const QString &articleTitle) co
// If this is a REPACK and PROPER download, add the individual entries to the list
// so we don't download those
if (isRepack && isProper) {
if (isRepack && isProper)
{
m_dataPtr->lastComputedEpisodes.append(episodeStr + QLatin1String("-REPACK"));
m_dataPtr->lastComputedEpisodes.append(episodeStr + QLatin1String("-PROPER"));
}
@@ -378,7 +396,8 @@ bool AutoDownloadRule::matchesSmartEpisodeFilter(const QString &articleTitle) co
bool AutoDownloadRule::matches(const QVariantHash &articleData) const
{
const QDateTime articleDate {articleData[Article::KeyDate].toDateTime()};
if (ignoreDays() > 0) {
if (ignoreDays() > 0)
{
if (lastMatch().isValid() && (articleDate < lastMatch().addDays(ignoreDays())))
return false;
}
@@ -404,7 +423,8 @@ bool AutoDownloadRule::accepts(const QVariantHash &articleData)
setLastMatch(articleData[Article::KeyDate].toDateTime());
// If there's a matched episode string, add that to the previously matched list
if (!m_dataPtr->lastComputedEpisodes.isEmpty()) {
if (!m_dataPtr->lastComputedEpisodes.isEmpty())
{
m_dataPtr->previouslyMatchedEpisodes.append(m_dataPtr->lastComputedEpisodes);
m_dataPtr->lastComputedEpisodes.clear();
}
@@ -474,10 +494,12 @@ AutoDownloadRule AutoDownloadRule::fromJsonObject(const QJsonObject &jsonObj, co
const QJsonValue previouslyMatchedVal = jsonObj.value(Str_PreviouslyMatched);
QStringList previouslyMatched;
if (previouslyMatchedVal.isString()) {
if (previouslyMatchedVal.isString())
{
previouslyMatched << previouslyMatchedVal.toString();
}
else {
else
{
for (const QJsonValue &val : asConst(previouslyMatchedVal.toArray()))
previouslyMatched << val.toString();
}

View File

@@ -69,7 +69,8 @@ Feed::Feed(const QUuid &uid, const QString &url, const QString &path, Session *s
m_dataFileName = QString::fromLatin1(m_uid.toRfc4122().toHex()) + QLatin1String(".json");
// Move to new file naming scheme (since v4.1.2)
const QString legacyFilename {Utils::Fs::toValidFileSystemName(m_url, false, QLatin1String("_"))
const QString legacyFilename
{Utils::Fs::toValidFileSystemName(m_url, false, QLatin1String("_"))
+ QLatin1String(".json")};
const QDir storageDir {m_session->dataFileStorage()->storageDir()};
if (!QFile::exists(storageDir.absoluteFilePath(m_dataFileName)))
@@ -106,8 +107,10 @@ QList<Article *> Feed::articles() const
void Feed::markAsRead()
{
const int oldUnreadCount = m_unreadCount;
for (Article *article : asConst(m_articles)) {
if (!article->isRead()) {
for (Article *article : asConst(m_articles))
{
if (!article->isRead())
{
article->disconnect(this);
article->markAsRead();
--m_unreadCount;
@@ -115,7 +118,8 @@ void Feed::markAsRead()
}
}
if (m_unreadCount != oldUnreadCount) {
if (m_unreadCount != oldUnreadCount)
{
m_dirty = true;
store();
emit unreadCountChanged(this);
@@ -180,7 +184,8 @@ void Feed::handleMaxArticlesPerFeedChanged(const int n)
void Feed::handleIconDownloadFinished(const Net::DownloadResult &result)
{
if (result.status == Net::DownloadStatus::Success) {
if (result.status == Net::DownloadStatus::Success)
{
m_iconPath = Utils::Fs::toUniformPath(result.filePath);
emit iconLoaded(this);
}
@@ -195,13 +200,15 @@ void Feed::handleDownloadFinished(const Net::DownloadResult &result)
{
m_downloadHandler = nullptr; // will be deleted by DownloadManager later
if (result.status == Net::DownloadStatus::Success) {
if (result.status == Net::DownloadStatus::Success)
{
LogMsg(tr("RSS feed at '%1' is successfully downloaded. Starting to parse it.")
.arg(result.url));
// Parse the download RSS
m_parser->parse(result.data);
}
else {
else
{
m_isLoading = false;
m_hasError = true;
@@ -216,13 +223,15 @@ void Feed::handleParsingFinished(const RSS::Private::ParsingResult &result)
{
m_hasError = !result.error.isEmpty();
if (!result.title.isEmpty() && (title() != result.title)) {
if (!result.title.isEmpty() && (title() != result.title))
{
m_title = result.title;
m_dirty = true;
emit titleChanged(this);
}
if (!result.lastBuildDate.isEmpty()) {
if (!result.lastBuildDate.isEmpty())
{
m_lastBuildDate = result.lastBuildDate;
m_dirty = true;
}
@@ -234,7 +243,8 @@ void Feed::handleParsingFinished(const RSS::Private::ParsingResult &result)
const int newArticlesCount = updateArticles(result.articles);
store();
if (m_hasError) {
if (m_hasError)
{
LogMsg(tr("Failed to parse RSS feed at '%1'. Reason: %2").arg(m_url, result.error)
, Log::WARNING);
}
@@ -249,16 +259,19 @@ void Feed::load()
{
QFile file(m_session->dataFileStorage()->storageDir().absoluteFilePath(m_dataFileName));
if (!file.exists()) {
if (!file.exists())
{
loadArticlesLegacy();
m_dirty = true;
store(); // convert to new format
}
else if (file.open(QFile::ReadOnly)) {
else if (file.open(QFile::ReadOnly))
{
loadArticles(file.readAll());
file.close();
}
else {
else
{
LogMsg(tr("Couldn't read RSS Session data from %1. Error: %2")
.arg(m_dataFileName, file.errorString())
, Log::WARNING);
@@ -269,28 +282,33 @@ void Feed::loadArticles(const QByteArray &data)
{
QJsonParseError jsonError;
const QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
if (jsonError.error != QJsonParseError::NoError) {
if (jsonError.error != QJsonParseError::NoError)
{
LogMsg(tr("Couldn't parse RSS Session data. Error: %1").arg(jsonError.errorString())
, Log::WARNING);
return;
}
if (!jsonDoc.isArray()) {
if (!jsonDoc.isArray())
{
LogMsg(tr("Couldn't load RSS Session data. Invalid data format."), Log::WARNING);
return;
}
const QJsonArray jsonArr = jsonDoc.array();
int i = -1;
for (const QJsonValue &jsonVal : jsonArr) {
for (const QJsonValue &jsonVal : jsonArr)
{
++i;
if (!jsonVal.isObject()) {
if (!jsonVal.isObject())
{
LogMsg(tr("Couldn't load RSS article '%1#%2'. Invalid data format.").arg(m_url).arg(i)
, Log::WARNING);
continue;
}
try {
try
{
auto article = new Article(this, jsonVal.toObject());
if (!addArticle(article))
delete article;
@@ -304,13 +322,15 @@ void Feed::loadArticlesLegacy()
const SettingsPtr qBTRSSFeeds = Profile::instance()->applicationSettings(QStringLiteral("qBittorrent-rss-feeds"));
const QVariantHash allOldItems = qBTRSSFeeds->value("old_items").toHash();
for (const QVariant &var : asConst(allOldItems.value(m_url).toList())) {
for (const QVariant &var : asConst(allOldItems.value(m_url).toList()))
{
auto hash = var.toHash();
// update legacy keys
hash[Article::KeyLink] = hash.take(QLatin1String("news_link"));
hash[Article::KeyTorrentURL] = hash.take(QLatin1String("torrent_url"));
hash[Article::KeyIsRead] = hash.take(QLatin1String("read"));
try {
try
{
auto article = new Article(this, hash);
if (!addArticle(article))
delete article;
@@ -353,7 +373,8 @@ bool Feed::addArticle(Article *article)
m_articles[article->guid()] = article;
m_articlesByDate.insert(lowerBound, article);
if (!article->isRead()) {
if (!article->isRead())
{
increaseUnreadCount();
connect(article, &Article::read, this, &Feed::handleArticleRead);
}
@@ -414,12 +435,14 @@ int Feed::updateArticles(const QList<QVariantHash> &loadedArticles)
QDateTime dummyPubDate {QDateTime::currentDateTime()};
QVector<QVariantHash> newArticles;
newArticles.reserve(loadedArticles.size());
for (QVariantHash article : loadedArticles) {
for (QVariantHash article : loadedArticles)
{
// If article has no publication date we use feed update time as a fallback.
// To prevent processing of "out-of-limit" articles we must not assign dates
// that are earlier than the dates of existing articles.
const Article *existingArticle = articleByGUID(article[Article::KeyId].toString());
if (existingArticle) {
if (existingArticle)
{
dummyPubDate = existingArticle->date().addMSecs(-1);
continue;
}
@@ -462,7 +485,8 @@ int Feed::updateArticles(const QList<QVariantHash> &loadedArticles)
int newArticlesCount = 0;
std::for_each(sortData.crbegin(), sortData.crend(), [this, &newArticlesCount](const ArticleSortAdaptor &a)
{
if (a.second) {
if (a.second)
{
addArticle(new Article {this, *a.second});
++newArticlesCount;
}
@@ -482,7 +506,8 @@ QJsonValue Feed::toJsonValue(const bool withData) const
jsonObj.insert(KEY_UID, uid().toString());
jsonObj.insert(KEY_URL, url());
if (withData) {
if (withData)
{
jsonObj.insert(KEY_TITLE, title());
jsonObj.insert(KEY_LASTBUILDDATE, lastBuildDate());
jsonObj.insert(KEY_ISLOADING, isLoading());
@@ -499,7 +524,8 @@ QJsonValue Feed::toJsonValue(const bool withData) const
void Feed::handleSessionProcessingEnabledChanged(const bool enabled)
{
if (enabled) {
if (enabled)
{
downloadIcon();
disconnect(m_session, &Session::processingStateChanged
, this, &Feed::handleSessionProcessingEnabledChanged);

View File

@@ -57,7 +57,8 @@ QList<Article *> Folder::articles() const
{
QList<Article *> news;
for (Item *item : asConst(items())) {
for (Item *item : asConst(items()))
{
int n = news.size();
news << item->articles();
std::inplace_merge(news.begin(), news.begin() + n, news.end()

View File

@@ -47,7 +47,8 @@ Item::~Item() {}
void Item::setPath(const QString &path)
{
if (path != m_path) {
if (path != m_path)
{
m_path = path;
emit pathChanged(this);
}
@@ -69,7 +70,8 @@ bool Item::isValidPath(const QString &path)
QString(R"(\A[^\%1]+(\%1[^\%1]+)*\z)").arg(Item::PathSeparator)
, QRegularExpression::DontCaptureOption);
if (path.isEmpty() || !re.match(path).hasMatch()) {
if (path.isEmpty() || !re.match(path).hasMatch())
{
qDebug() << "Incorrect RSS Item path:" << path;
return false;
}
@@ -93,7 +95,8 @@ QStringList Item::expandPath(const QString &path)
// return result;
int index = 0;
while ((index = path.indexOf(Item::PathSeparator, index)) >= 0) {
while ((index = path.indexOf(Item::PathSeparator, index)) >= 0)
{
result << path.left(index);
++index;
}

View File

@@ -53,7 +53,8 @@ namespace
// http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent
// http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent
// http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent
static const QHash<QString, QString> HTMLEntities {
static const QHash<QString, QString> HTMLEntities
{
{"nbsp", "&#160;"}, // no-break space = non-breaking space, U+00A0 ISOnum
{"iexcl", "&#161;"}, // inverted exclamation mark, U+00A1 ISOnum
{"cent", "&#162;"}, // cent sign, U+00A2 ISOnum
@@ -359,17 +360,20 @@ namespace
// Ported to Qt from KDElibs4
QDateTime parseDate(const QString &string)
{
const char shortDay[][4] = {
const char shortDay[][4] =
{
"Mon", "Tue", "Wed",
"Thu", "Fri", "Sat",
"Sun"
};
const char longDay[][10] = {
const char longDay[][10] =
{
"Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday",
"Sunday"
};
const char shortMonth[][4] = {
const char shortMonth[][4] =
{
"Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec"
@@ -389,7 +393,8 @@ namespace
// Also accept obsolete form "Weekday, DD-Mon-YY HH:MM:SS ±hhmm"
QRegExp rx("^(?:([A-Z][a-z]+),\\s*)?(\\d{1,2})(\\s+|-)([^-\\s]+)(\\s+|-)(\\d{2,4})\\s+(\\d\\d):(\\d\\d)(?::(\\d\\d))?\\s+(\\S+)$");
QStringList parts;
if (!str.indexOf(rx)) {
if (!str.indexOf(rx))
{
// Check that if date has '-' separators, both separators are '-'.
parts = rx.capturedTexts();
const bool h1 = (parts[3] == QLatin1String("-"));
@@ -397,7 +402,8 @@ namespace
if (h1 != h2)
return QDateTime::currentDateTime();
}
else {
else
{
// Check for the obsolete form "Wdy Mon DD HH:MM:SS YYYY"
rx = QRegExp("^([A-Z][a-z]+)\\s+(\\S+)\\s+(\\d\\d)\\s+(\\d\\d):(\\d\\d):(\\d\\d)\\s+(\\d\\d\\d\\d)$");
if (str.indexOf(rx))
@@ -421,7 +427,8 @@ namespace
return QDateTime::currentDateTime();
int second = 0;
if (!parts[nsec].isEmpty()) {
if (!parts[nsec].isEmpty())
{
second = parts[nsec].toInt(&ok[0]);
if (!ok[0])
return QDateTime::currentDateTime();
@@ -433,7 +440,8 @@ namespace
int month = 0;
for ( ; (month < 12) && (parts[nmonth] != shortMonth[month]); ++month);
int dayOfWeek = -1;
if (!parts[nwday].isEmpty()) {
if (!parts[nwday].isEmpty())
{
// Look up the weekday name
while ((++dayOfWeek < 7) && (shortDay[dayOfWeek] != parts[nwday]));
if (dayOfWeek >= 7)
@@ -444,7 +452,8 @@ namespace
// || (dayOfWeek < 0 && format == RFCDateDay))
// return QDateTime;
const int i = parts[nyear].size();
if (i < 4) {
if (i < 4)
{
// It's an obsolete year specification with less than 4 digits
year += ((i == 2) && (year < 50)) ? 2000 : 1900;
}
@@ -452,9 +461,11 @@ namespace
// Parse the UTC offset part
int offset = 0; // set default to '-0000'
bool negOffset = false;
if (parts.count() > 10) {
if (parts.count() > 10)
{
rx = QRegExp("^([+-])(\\d\\d)(\\d\\d)$");
if (!parts[10].indexOf(rx)) {
if (!parts[10].indexOf(rx))
{
// It's a UTC offset ±hhmm
parts = rx.capturedTexts();
offset = parts[2].toInt(&ok[0]) * 3600;
@@ -466,13 +477,16 @@ namespace
if (negOffset)
offset = -offset;
}
else {
else
{
// Check for an obsolete time zone name
const QByteArray zone = parts[10].toLatin1();
if ((zone.length() == 1) && (isalpha(zone[0])) && (toupper(zone[0]) != 'J')) {
if ((zone.length() == 1) && (isalpha(zone[0])) && (toupper(zone[0]) != 'J'))
{
negOffset = true; // military zone: RFC 2822 treats as '-0000'
}
else if ((zone != "UT") && (zone != "GMT")) { // treated as '+0000'
else if ((zone != "UT") && (zone != "GMT"))
{ // treated as '+0000'
offset = (zone == "EDT")
? -4 * 3600
: ((zone == "EST") || (zone == "CDT"))
@@ -484,7 +498,8 @@ namespace
: (zone == "PST")
? -8 * 3600
: 0;
if (!offset) {
if (!offset)
{
// Check for any other alphabetic time zone
bool nonalpha = false;
for (int i = 0, end = zone.size(); (i < end) && !nonalpha; ++i)
@@ -509,7 +524,8 @@ namespace
if (!result.isValid())
return QDateTime::currentDateTime(); // invalid date/time
if (leapSecond) {
if (leapSecond)
{
// Validate a leap second time. Leap seconds are inserted after 23:59:59 UTC.
// Convert the time to UTC and check that it is 00:00:00.
if ((hour*3600 + minute*60 + 60 - offset + 86400*5) % 86400) // (max abs(offset) is 100 hours)
@@ -548,11 +564,15 @@ void Parser::parse_impl(const QByteArray &feedData)
xml.setEntityResolver(&resolver);
bool foundChannel = false;
while (xml.readNextStartElement()) {
if (xml.name() == "rss") {
while (xml.readNextStartElement())
{
if (xml.name() == "rss")
{
// Find channels
while (xml.readNextStartElement()) {
if (xml.name() == "channel") {
while (xml.readNextStartElement())
{
if (xml.name() == "channel")
{
parseRSSChannel(xml);
foundChannel = true;
break;
@@ -563,7 +583,8 @@ void Parser::parse_impl(const QByteArray &feedData)
}
break;
}
if (xml.name() == "feed") { // Atom feed
if (xml.name() == "feed")
{ // Atom feed
parseAtomChannel(xml);
foundChannel = true;
break;
@@ -573,10 +594,12 @@ void Parser::parse_impl(const QByteArray &feedData)
xml.skipCurrentElement();
}
if (!foundChannel) {
if (!foundChannel)
{
m_result.error = tr("Invalid RSS feed.");
}
else if (xml.hasError()) {
else if (xml.hasError())
{
m_result.error = tr("%1 (line: %2, column: %3, offset: %4).")
.arg(xml.errorString()).arg(xml.lineNumber())
.arg(xml.columnNumber()).arg(xml.characterOffset());
@@ -592,43 +615,53 @@ void Parser::parseRssArticle(QXmlStreamReader &xml)
QVariantHash article;
QString altTorrentUrl;
while (!xml.atEnd()) {
while (!xml.atEnd())
{
xml.readNext();
const QString name(xml.name().toString());
if (xml.isEndElement() && (name == QLatin1String("item")))
break;
if (xml.isStartElement()) {
if (name == QLatin1String("title")) {
if (xml.isStartElement())
{
if (name == QLatin1String("title"))
{
article[Article::KeyTitle] = xml.readElementText().trimmed();
}
else if (name == QLatin1String("enclosure")) {
else if (name == QLatin1String("enclosure"))
{
if (xml.attributes().value("type") == QLatin1String("application/x-bittorrent"))
article[Article::KeyTorrentURL] = xml.attributes().value(QLatin1String("url")).toString();
else if (xml.attributes().value("type").isEmpty())
altTorrentUrl = xml.attributes().value(QLatin1String("url")).toString();
}
else if (name == QLatin1String("link")) {
else if (name == QLatin1String("link"))
{
const QString text {xml.readElementText().trimmed()};
if (text.startsWith(QLatin1String("magnet:"), Qt::CaseInsensitive))
article[Article::KeyTorrentURL] = text; // magnet link instead of a news URL
else
article[Article::KeyLink] = text;
}
else if (name == QLatin1String("description")) {
else if (name == QLatin1String("description"))
{
article[Article::KeyDescription] = xml.readElementText(QXmlStreamReader::IncludeChildElements);
}
else if (name == QLatin1String("pubDate")) {
else if (name == QLatin1String("pubDate"))
{
article[Article::KeyDate] = parseDate(xml.readElementText().trimmed());
}
else if (name == QLatin1String("author")) {
else if (name == QLatin1String("author"))
{
article[Article::KeyAuthor] = xml.readElementText().trimmed();
}
else if (name == QLatin1String("guid")) {
else if (name == QLatin1String("guid"))
{
article[Article::KeyId] = xml.readElementText().trimmed();
}
else {
else
{
article[name] = xml.readElementText(QXmlStreamReader::IncludeChildElements);
}
}
@@ -642,24 +675,31 @@ void Parser::parseRssArticle(QXmlStreamReader &xml)
void Parser::parseRSSChannel(QXmlStreamReader &xml)
{
while (!xml.atEnd()) {
while (!xml.atEnd())
{
xml.readNext();
if (xml.isStartElement()) {
if (xml.name() == QLatin1String("title")) {
if (xml.isStartElement())
{
if (xml.name() == QLatin1String("title"))
{
m_result.title = xml.readElementText();
}
else if (xml.name() == QLatin1String("lastBuildDate")) {
else if (xml.name() == QLatin1String("lastBuildDate"))
{
const QString lastBuildDate = xml.readElementText();
if (!lastBuildDate.isEmpty()) {
if (m_result.lastBuildDate == lastBuildDate) {
if (!lastBuildDate.isEmpty())
{
if (m_result.lastBuildDate == lastBuildDate)
{
qDebug() << "The RSS feed has not changed since last time, aborting parsing.";
return;
}
m_result.lastBuildDate = lastBuildDate;
}
}
else if (xml.name() == QLatin1String("item")) {
else if (xml.name() == QLatin1String("item"))
{
parseRssArticle(xml);
}
}
@@ -671,18 +711,22 @@ void Parser::parseAtomArticle(QXmlStreamReader &xml)
QVariantHash article;
bool doubleContent = false;
while (!xml.atEnd()) {
while (!xml.atEnd())
{
xml.readNext();
const QString name(xml.name().toString());
if (xml.isEndElement() && (name == QLatin1String("entry")))
break;
if (xml.isStartElement()) {
if (name == QLatin1String("title")) {
if (xml.isStartElement())
{
if (name == QLatin1String("title"))
{
article[Article::KeyTitle] = xml.readElementText().trimmed();
}
else if (name == QLatin1String("link")) {
else if (name == QLatin1String("link"))
{
const QString link = (xml.attributes().isEmpty()
? xml.readElementText().trimmed()
: xml.attributes().value(QLatin1String("href")).toString());
@@ -696,8 +740,10 @@ void Parser::parseAtomArticle(QXmlStreamReader &xml)
article[Article::KeyLink] = (m_baseUrl.isEmpty() ? link : m_baseUrl + link);
}
else if ((name == QLatin1String("summary")) || (name == QLatin1String("content"))) {
if (doubleContent) { // Duplicate content -> ignore
else if ((name == QLatin1String("summary")) || (name == QLatin1String("content")))
{
if (doubleContent)
{ // Duplicate content -> ignore
xml.skipCurrentElement();
continue;
}
@@ -705,28 +751,34 @@ void Parser::parseAtomArticle(QXmlStreamReader &xml)
// Try to also parse broken articles, which don't use html '&' escapes
// Actually works great for non-broken content too
const QString feedText = xml.readElementText(QXmlStreamReader::IncludeChildElements).trimmed();
if (!feedText.isEmpty()) {
if (!feedText.isEmpty())
{
article[Article::KeyDescription] = feedText;
doubleContent = true;
}
}
else if (name == QLatin1String("updated")) {
else if (name == QLatin1String("updated"))
{
// ATOM uses standard compliant date, don't do fancy stuff
const QDateTime articleDate = QDateTime::fromString(xml.readElementText().trimmed(), Qt::ISODate);
article[Article::KeyDate] = (articleDate.isValid() ? articleDate : QDateTime::currentDateTime());
}
else if (name == QLatin1String("author")) {
while (xml.readNextStartElement()) {
else if (name == QLatin1String("author"))
{
while (xml.readNextStartElement())
{
if (xml.name() == QLatin1String("name"))
article[Article::KeyAuthor] = xml.readElementText().trimmed();
else
xml.skipCurrentElement();
}
}
else if (name == QLatin1String("id")) {
else if (name == QLatin1String("id"))
{
article[Article::KeyId] = xml.readElementText().trimmed();
}
else {
else
{
article[name] = xml.readElementText(QXmlStreamReader::IncludeChildElements);
}
}
@@ -739,24 +791,31 @@ void Parser::parseAtomChannel(QXmlStreamReader &xml)
{
m_baseUrl = xml.attributes().value("xml:base").toString();
while (!xml.atEnd()) {
while (!xml.atEnd())
{
xml.readNext();
if (xml.isStartElement()) {
if (xml.name() == QLatin1String("title")) {
if (xml.isStartElement())
{
if (xml.name() == QLatin1String("title"))
{
m_result.title = xml.readElementText();
}
else if (xml.name() == QLatin1String("updated")) {
else if (xml.name() == QLatin1String("updated"))
{
const QString lastBuildDate = xml.readElementText();
if (!lastBuildDate.isEmpty()) {
if (m_result.lastBuildDate == lastBuildDate) {
if (!lastBuildDate.isEmpty())
{
if (m_result.lastBuildDate == lastBuildDate)
{
qDebug() << "The RSS feed has not changed since last time, aborting parsing.";
return;
}
m_result.lastBuildDate = lastBuildDate;
}
}
else if (xml.name() == QLatin1String("entry")) {
else if (xml.name() == QLatin1String("entry"))
{
parseAtomArticle(xml);
}
}
@@ -776,14 +835,16 @@ void Parser::addArticle(QVariantHash article)
if (localId.toString().isEmpty())
localId = article.value(Article::KeyTitle);
if (localId.toString().isEmpty()) {
if (localId.toString().isEmpty())
{
// The article could not be uniquely identified
// since it has no appropriate data.
// Just ignore it.
return;
}
if (m_articleIDs.contains(localId.toString())) {
if (m_articleIDs.contains(localId.toString()))
{
// The article could not be uniquely identified
// since the Feed has duplicate identifiers.
// Just ignore it.

View File

@@ -97,7 +97,8 @@ Session::Session()
load();
connect(&m_refreshTimer, &QTimer::timeout, this, &Session::refresh);
if (m_processingEnabled) {
if (m_processingEnabled)
{
m_refreshTimer.start(m_refreshInterval * MsecsPerMin);
refresh();
}
@@ -155,7 +156,8 @@ bool Session::addFolder(const QString &path, QString *error)
bool Session::addFeed(const QString &url, const QString &path, QString *error)
{
if (m_feedsByURL.contains(url)) {
if (m_feedsByURL.contains(url))
{
if (error)
*error = tr("RSS feed with given URL already exists: %1.").arg(url);
return false;
@@ -174,14 +176,16 @@ bool Session::addFeed(const QString &url, const QString &path, QString *error)
bool Session::moveItem(const QString &itemPath, const QString &destPath, QString *error)
{
if (itemPath.isEmpty()) {
if (itemPath.isEmpty())
{
if (error)
*error = tr("Cannot move root folder.");
return false;
}
auto item = m_itemsByPath.value(itemPath);
if (!item) {
if (!item)
{
if (error)
*error = tr("Item doesn't exist: %1.").arg(itemPath);
return false;
@@ -200,7 +204,8 @@ bool Session::moveItem(Item *item, const QString &destPath, QString *error)
return false;
auto srcFolder = static_cast<Folder *>(m_itemsByPath.value(Item::parentPath(item->path())));
if (srcFolder != destFolder) {
if (srcFolder != destFolder)
{
srcFolder->removeItem(item);
destFolder->addItem(item);
}
@@ -212,14 +217,16 @@ bool Session::moveItem(Item *item, const QString &destPath, QString *error)
bool Session::removeItem(const QString &itemPath, QString *error)
{
if (itemPath.isEmpty()) {
if (itemPath.isEmpty())
{
if (error)
*error = tr("Cannot delete root folder.");
return false;
}
auto item = m_itemsByPath.value(itemPath);
if (!item) {
if (!item)
{
if (error)
*error = tr("Item doesn't exist: %1.").arg(itemPath);
return false;
@@ -248,12 +255,14 @@ Item *Session::itemByPath(const QString &path) const
void Session::load()
{
QFile itemsFile(m_confFileStorage->storageDir().absoluteFilePath(FeedsFileName));
if (!itemsFile.exists()) {
if (!itemsFile.exists())
{
loadLegacy();
return;
}
if (!itemsFile.open(QFile::ReadOnly)) {
if (!itemsFile.open(QFile::ReadOnly))
{
Logger::instance()->addMessage(
QString("Couldn't read RSS Session data from %1. Error: %2")
.arg(itemsFile.fileName(), itemsFile.errorString()), Log::WARNING);
@@ -262,14 +271,16 @@ void Session::load()
QJsonParseError jsonError;
const QJsonDocument jsonDoc = QJsonDocument::fromJson(itemsFile.readAll(), &jsonError);
if (jsonError.error != QJsonParseError::NoError) {
if (jsonError.error != QJsonParseError::NoError)
{
Logger::instance()->addMessage(
QString("Couldn't parse RSS Session data from %1. Error: %2")
.arg(itemsFile.fileName(), jsonError.errorString()), Log::WARNING);
return;
}
if (!jsonDoc.isObject()) {
if (!jsonDoc.isObject())
{
Logger::instance()->addMessage(
QString("Couldn't load RSS Session data from %1. Invalid data format.")
.arg(itemsFile.fileName()), Log::WARNING);
@@ -282,9 +293,11 @@ void Session::load()
void Session::loadFolder(const QJsonObject &jsonObj, Folder *folder)
{
bool updated = false;
for (const QString &key : asConst(jsonObj.keys())) {
for (const QString &key : asConst(jsonObj.keys()))
{
const QJsonValue val {jsonObj[key]};
if (val.isString()) {
if (val.isString())
{
// previous format (reduced form) doesn't contain UID
QString url = val.toString();
if (url.isEmpty())
@@ -292,31 +305,38 @@ void Session::loadFolder(const QJsonObject &jsonObj, Folder *folder)
addFeedToFolder(generateUID(), url, key, folder);
updated = true;
}
else if (val.isObject()) {
else if (val.isObject())
{
const QJsonObject valObj {val.toObject()};
if (valObj.contains("url")) {
if (!valObj["url"].isString()) {
if (valObj.contains("url"))
{
if (!valObj["url"].isString())
{
LogMsg(tr("Couldn't load RSS Feed '%1'. URL is required.")
.arg(QString("%1\\%2").arg(folder->path(), key)), Log::WARNING);
continue;
}
QUuid uid;
if (valObj.contains("uid")) {
if (valObj.contains("uid"))
{
uid = QUuid {valObj["uid"].toString()};
if (uid.isNull()) {
if (uid.isNull())
{
LogMsg(tr("Couldn't load RSS Feed '%1'. UID is invalid.")
.arg(QString("%1\\%2").arg(folder->path(), key)), Log::WARNING);
continue;
}
if (m_feedsByUID.contains(uid)) {
if (m_feedsByUID.contains(uid))
{
LogMsg(tr("Duplicate RSS Feed UID: %1. Configuration seems to be corrupted.")
.arg(uid.toString()), Log::WARNING);
continue;
}
}
else {
else
{
// previous format doesn't contain UID
uid = generateUID();
updated = true;
@@ -324,11 +344,13 @@ void Session::loadFolder(const QJsonObject &jsonObj, Folder *folder)
addFeedToFolder(uid, valObj["url"].toString(), key, folder);
}
else {
else
{
loadFolder(valObj, addSubfolder(key, folder));
}
}
else {
else
{
LogMsg(tr("Couldn't load RSS Item '%1'. Invalid data format.")
.arg(QString::fromLatin1("%1\\%2").arg(folder->path(), key)), Log::WARNING);
}
@@ -342,13 +364,15 @@ void Session::loadLegacy()
{
const QStringList legacyFeedPaths = SettingsStorage::instance()->loadValue("Rss/streamList").toStringList();
const QStringList feedAliases = SettingsStorage::instance()->loadValue("Rss/streamAlias").toStringList();
if (legacyFeedPaths.size() != feedAliases.size()) {
if (legacyFeedPaths.size() != feedAliases.size())
{
Logger::instance()->addMessage("Corrupted RSS list, not loading it.", Log::WARNING);
return;
}
uint i = 0;
for (QString legacyPath : legacyFeedPaths) {
for (QString legacyPath : legacyFeedPaths)
{
if (Item::PathSeparator == QString(legacyPath[0]))
legacyPath.remove(0, 1);
const QString parentFolderPath = Item::parentPath(legacyPath);
@@ -374,13 +398,15 @@ void Session::store()
Folder *Session::prepareItemDest(const QString &path, QString *error)
{
if (!Item::isValidPath(path)) {
if (!Item::isValidPath(path))
{
if (error)
*error = tr("Incorrect RSS Item path: %1.").arg(path);
return nullptr;
}
if (m_itemsByPath.contains(path)) {
if (m_itemsByPath.contains(path))
{
if (error)
*error = tr("RSS item with given path already exists: %1.").arg(path);
return nullptr;
@@ -388,7 +414,8 @@ Folder *Session::prepareItemDest(const QString &path, QString *error)
const QString destFolderPath = Item::parentPath(path);
auto destFolder = qobject_cast<Folder *>(m_itemsByPath.value(destFolderPath));
if (!destFolder) {
if (!destFolder)
{
if (error)
*error = tr("Parent folder doesn't exist: %1.").arg(destFolderPath);
return nullptr;
@@ -413,7 +440,8 @@ Feed *Session::addFeedToFolder(const QUuid &uid, const QString &url, const QStri
void Session::addItem(Item *item, Folder *destFolder)
{
if (auto feed = qobject_cast<Feed *>(item)) {
if (auto feed = qobject_cast<Feed *>(item))
{
connect(feed, &Feed::titleChanged, this, &Session::handleFeedTitleChanged);
connect(feed, &Feed::iconLoaded, this, &Session::feedIconLoaded);
connect(feed, &Feed::stateChanged, this, &Session::feedStateChanged);
@@ -435,14 +463,17 @@ bool Session::isProcessingEnabled() const
void Session::setProcessingEnabled(bool enabled)
{
if (m_processingEnabled != enabled) {
if (m_processingEnabled != enabled)
{
m_processingEnabled = enabled;
SettingsStorage::instance()->storeValue(SettingsKey_ProcessingEnabled, m_processingEnabled);
if (m_processingEnabled) {
if (m_processingEnabled)
{
m_refreshTimer.start(m_refreshInterval * MsecsPerMin);
refresh();
}
else {
else
{
m_refreshTimer.stop();
}
@@ -482,7 +513,8 @@ int Session::refreshInterval() const
void Session::setRefreshInterval(const int refreshInterval)
{
if (m_refreshInterval != refreshInterval) {
if (m_refreshInterval != refreshInterval)
{
SettingsStorage::instance()->storeValue(SettingsKey_RefreshInterval, refreshInterval);
m_refreshInterval = refreshInterval;
m_refreshTimer.start(m_refreshInterval * MsecsPerMin);
@@ -498,7 +530,8 @@ void Session::handleItemAboutToBeDestroyed(Item *item)
{
m_itemsByPath.remove(item->path());
auto feed = qobject_cast<Feed *>(item);
if (feed) {
if (feed)
{
m_feedsByUID.remove(feed->uid());
m_feedsByURL.remove(feed->url());
}
@@ -528,7 +561,8 @@ int Session::maxArticlesPerFeed() const
void Session::setMaxArticlesPerFeed(const int n)
{
if (m_maxArticlesPerFeed != n) {
if (m_maxArticlesPerFeed != n)
{
m_maxArticlesPerFeed = n;
SettingsStorage::instance()->storeValue(SettingsKey_MaxArticlesPerFeed, n);
emit maxArticlesPerFeedChanged(n);

View File

@@ -34,20 +34,26 @@
* RSS Session configuration file format (JSON):
*
* =============== BEGIN ===============
* {
* "folder1": {
* "subfolder1": {
* "Feed name 1 (Alias)": {
*
{
* "folder1":
{
* "subfolder1":
{
* "Feed name 1 (Alias)":
{
* "uid": "feed unique identifier",
* "url": "http://some-feed-url1"
* }
* "Feed name 2 (Alias)": {
* "Feed name 2 (Alias)":
{
* "uid": "feed unique identifier",
* "url": "http://some-feed-url2"
* }
* },
* "subfolder2": {},
* "Feed name 3 (Alias)": {
* "Feed name 3 (Alias)":
{
* "uid": "feed unique identifier",
* "url": "http://some-feed-url3"
* }

View File

@@ -106,17 +106,21 @@ QVariant ScanFoldersModel::data(const QModelIndex &index, int role) const
const PathData *pathData = m_pathList.at(index.row());
QVariant value;
switch (index.column()) {
switch (index.column())
{
case WATCH:
if (role == Qt::DisplayRole)
value = Utils::Fs::toNativePath(pathData->watchPath);
break;
case DOWNLOAD:
if (role == Qt::UserRole) {
if (role == Qt::UserRole)
{
value = pathData->downloadType;
}
else if (role == Qt::DisplayRole) {
switch (pathData->downloadType) {
else if (role == Qt::DisplayRole)
{
switch (pathData->downloadType)
{
case DOWNLOAD_IN_WATCH_FOLDER:
case DEFAULT_LOCATION:
value = pathTypeDisplayName(pathData->downloadType);
@@ -139,7 +143,8 @@ QVariant ScanFoldersModel::headerData(int section, Qt::Orientation orientation,
QVariant title;
switch (section) {
switch (section)
{
case WATCH:
title = tr("Monitored Folder");
break;
@@ -158,7 +163,8 @@ Qt::ItemFlags ScanFoldersModel::flags(const QModelIndex &index) const
Qt::ItemFlags flags;
switch (index.column()) {
switch (index.column())
{
case WATCH:
flags = QAbstractListModel::flags(index);
break;
@@ -176,7 +182,8 @@ bool ScanFoldersModel::setData(const QModelIndex &index, const QVariant &value,
|| (index.column() != DOWNLOAD))
return false;
if (role == Qt::UserRole) {
if (role == Qt::UserRole)
{
const auto type = static_cast<PathType>(value.toInt());
if (type == CUSTOM_LOCATION)
return false;
@@ -185,7 +192,8 @@ bool ScanFoldersModel::setData(const QModelIndex &index, const QVariant &value,
m_pathList[index.row()]->downloadPath.clear();
emit dataChanged(index, index);
}
else if (role == Qt::DisplayRole) {
else if (role == Qt::DisplayRole)
{
const QString path = value.toString();
if (path.isEmpty()) // means we didn't pass CUSTOM_LOCATION type
return false;
@@ -194,7 +202,8 @@ bool ScanFoldersModel::setData(const QModelIndex &index, const QVariant &value,
m_pathList[index.row()]->downloadPath = Utils::Fs::toNativePath(path);
emit dataChanged(index, index);
}
else {
else
{
return false;
}
@@ -213,7 +222,8 @@ ScanFoldersModel::PathStatus ScanFoldersModel::addPath(const QString &watchPath,
const QDir downloadDir(downloadPath);
const QString canonicalDownloadPath = downloadDir.canonicalPath();
if (!m_fsWatcher) {
if (!m_fsWatcher)
{
m_fsWatcher = new FileSystemWatcher(this);
connect(m_fsWatcher, &FileSystemWatcher::torrentsAdded, this, &ScanFoldersModel::addTorrentsToSession);
}
@@ -249,7 +259,8 @@ void ScanFoldersModel::addToFSWatcher(const QStringList &watchPaths)
if (!m_fsWatcher)
return; // addPath() wasn't called before this
for (const QString &path : watchPaths) {
for (const QString &path : watchPaths)
{
const QDir watchDir(path);
const QString canonicalWatchPath = watchDir.canonicalPath();
m_fsWatcher->addPath(canonicalWatchPath);
@@ -321,7 +332,8 @@ void ScanFoldersModel::makePersistent()
{
QVariantHash dirs;
for (const PathData *pathData : asConst(m_pathList)) {
for (const PathData *pathData : asConst(m_pathList))
{
if (pathData->downloadType == CUSTOM_LOCATION)
dirs.insert(Utils::Fs::toUniformPath(pathData->watchPath), Utils::Fs::toUniformPath(pathData->downloadPath));
else
@@ -335,7 +347,8 @@ void ScanFoldersModel::configure()
{
const QVariantHash dirs = Preferences::instance()->getScanDirs();
for (auto i = dirs.cbegin(); i != dirs.cend(); ++i) {
for (auto i = dirs.cbegin(); i != dirs.cend(); ++i)
{
if (i.value().type() == QVariant::Int)
addPath(i.key(), static_cast<PathType>(i.value().toInt()), QString());
else
@@ -345,22 +358,27 @@ void ScanFoldersModel::configure()
void ScanFoldersModel::addTorrentsToSession(const QStringList &pathList)
{
for (const QString &file : pathList) {
for (const QString &file : pathList)
{
qDebug("File %s added", qUtf8Printable(file));
BitTorrent::AddTorrentParams params;
if (downloadInWatchFolder(file)) {
if (downloadInWatchFolder(file))
{
params.savePath = QFileInfo(file).dir().path();
params.useAutoTMM = TriStateBool::False;
}
else if (!downloadInDefaultFolder(file)) {
else if (!downloadInDefaultFolder(file))
{
params.savePath = downloadPathTorrentFolder(file);
params.useAutoTMM = TriStateBool::False;
}
if (file.endsWith(".magnet", Qt::CaseInsensitive)) {
if (file.endsWith(".magnet", Qt::CaseInsensitive))
{
QFile f(file);
if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
if (f.open(QIODevice::ReadOnly | QIODevice::Text))
{
QTextStream str(&f);
while (!str.atEnd())
BitTorrent::Session::instance()->addTorrent(str.readLine(), params);
@@ -368,17 +386,21 @@ void ScanFoldersModel::addTorrentsToSession(const QStringList &pathList)
f.close();
Utils::Fs::forceRemove(file);
}
else {
else
{
qDebug("Failed to open magnet file: %s", qUtf8Printable(f.errorString()));
}
}
else {
else
{
const BitTorrent::TorrentInfo torrentInfo = BitTorrent::TorrentInfo::loadFromFile(file);
if (torrentInfo.isValid()) {
if (torrentInfo.isValid())
{
BitTorrent::Session::instance()->addTorrent(torrentInfo, params);
Utils::Fs::forceRemove(file);
}
else {
else
{
qDebug("Ignoring incomplete torrent file: %s", qUtf8Printable(file));
}
}
@@ -387,7 +409,8 @@ void ScanFoldersModel::addTorrentsToSession(const QStringList &pathList)
QString ScanFoldersModel::pathTypeDisplayName(const PathType type)
{
switch (type) {
switch (type)
{
case DOWNLOAD_IN_WATCH_FOLDER:
return tr("Monitored folder");
case DEFAULT_LOCATION:

View File

@@ -42,7 +42,8 @@ SearchDownloadHandler::SearchDownloadHandler(const QString &siteUrl, const QStri
m_downloadProcess->setEnvironment(QProcess::systemEnvironment());
connect(m_downloadProcess, qOverload<int, QProcess::ExitStatus>(&QProcess::finished)
, this, &SearchDownloadHandler::downloadProcessFinished);
const QStringList params {
const QStringList params
{
Utils::Fs::toNativePath(m_manager->engineLocation() + "/nova2dl.py"),
siteUrl,
url
@@ -55,7 +56,8 @@ void SearchDownloadHandler::downloadProcessFinished(int exitcode)
{
QString path;
if ((exitcode == 0) && (m_downloadProcess->exitStatus() == QProcess::NormalExit)) {
if ((exitcode == 0) && (m_downloadProcess->exitStatus() == QProcess::NormalExit))
{
const QString line = QString::fromUtf8(m_downloadProcess->readAllStandardOutput()).trimmed();
const QVector<QStringRef> parts = line.splitRef(' ');
if (parts.size() == 2)

View File

@@ -64,7 +64,8 @@ SearchHandler::SearchHandler(const QString &pattern, const QString &category, co
// Load environment variables (proxy)
m_searchProcess->setEnvironment(QProcess::systemEnvironment());
const QStringList params {
const QStringList params
{
Utils::Fs::toNativePath(m_manager->engineLocation() + "/nova2.py"),
m_usedPlugins.join(','),
m_category
@@ -137,13 +138,15 @@ void SearchHandler::readSearchOutput()
QVector<SearchResult> searchResultList;
searchResultList.reserve(lines.size());
for (const QByteArray &line : asConst(lines)) {
for (const QByteArray &line : asConst(lines))
{
SearchResult searchResult;
if (parseSearchResult(QString::fromUtf8(line), searchResult))
searchResultList << searchResult;
}
if (!searchResultList.isEmpty()) {
if (!searchResultList.isEmpty())
{
for (const SearchResult &result : searchResultList)
m_results.append(result);
emit newSearchResults(searchResultList);

View File

@@ -61,16 +61,19 @@ namespace
while (iter.hasNext())
dirs += iter.next();
for (const QString &dir : asConst(dirs)) {
for (const QString &dir : asConst(dirs))
{
// python 3: remove "__pycache__" folders
if (dir.endsWith("/__pycache__")) {
if (dir.endsWith("/__pycache__"))
{
Utils::Fs::removeDirRecursive(dir);
continue;
}
// python 2: remove "*.pyc" files
const QStringList files = QDir(dir).entryList(QDir::Files);
for (const QString &file : files) {
for (const QString &file : files)
{
if (file.endsWith(".pyc"))
Utils::Fs::forceRemove(file);
}
@@ -115,7 +118,8 @@ QStringList SearchPluginManager::allPlugins() const
QStringList SearchPluginManager::enabledPlugins() const
{
QStringList plugins;
for (const PluginInfo *plugin : asConst(m_plugins)) {
for (const PluginInfo *plugin : asConst(m_plugins))
{
if (plugin->enabled)
plugins << plugin->name;
}
@@ -126,9 +130,12 @@ QStringList SearchPluginManager::enabledPlugins() const
QStringList SearchPluginManager::supportedCategories() const
{
QStringList result;
for (const PluginInfo *plugin : asConst(m_plugins)) {
if (plugin->enabled) {
for (const QString &cat : plugin->supportedCategories) {
for (const PluginInfo *plugin : asConst(m_plugins))
{
if (plugin->enabled)
{
for (const QString &cat : plugin->supportedCategories)
{
if (!result.contains(cat))
result << cat;
}
@@ -149,7 +156,8 @@ QStringList SearchPluginManager::getPluginCategories(const QString &pluginName)
plugins << pluginName.trimmed();
QSet<QString> categories;
for (const QString &name : asConst(plugins)) {
for (const QString &name : asConst(plugins))
{
const PluginInfo *plugin = pluginInfo(name);
if (!plugin) continue; // plugin wasn't found
for (const QString &category : plugin->supportedCategories)
@@ -167,7 +175,8 @@ PluginInfo *SearchPluginManager::pluginInfo(const QString &name) const
void SearchPluginManager::enablePlugin(const QString &name, const bool enabled)
{
PluginInfo *plugin = m_plugins.value(name, nullptr);
if (plugin) {
if (plugin)
{
plugin->enabled = enabled;
// Save to Hard disk
Preferences *const pref = Preferences::instance();
@@ -193,12 +202,14 @@ void SearchPluginManager::installPlugin(const QString &source)
{
clearPythonCache(engineLocation());
if (Net::DownloadManager::hasSupportedScheme(source)) {
if (Net::DownloadManager::hasSupportedScheme(source))
{
using namespace Net;
DownloadManager::instance()->download(DownloadRequest(source).saveToFile(true)
, this, &SearchPluginManager::pluginDownloadFinished);
}
else {
else
{
QString path = source;
if (path.startsWith("file:", Qt::CaseInsensitive))
path = QUrl(path).toLocalFile();
@@ -217,7 +228,8 @@ void SearchPluginManager::installPlugin_impl(const QString &name, const QString
{
const PluginVersion newVersion = getPluginVersion(path);
const PluginInfo *plugin = pluginInfo(name);
if (plugin && !(plugin->version < newVersion)) {
if (plugin && !(plugin->version < newVersion))
{
LogMsg(tr("Plugin already at version %1, which is greater than %2").arg(plugin->version, newVersion), Log::INFO);
emit pluginUpdateFailed(name, tr("A more recent version of this plugin is already installed."));
return;
@@ -226,7 +238,8 @@ void SearchPluginManager::installPlugin_impl(const QString &name, const QString
// Process with install
const QString destPath = pluginPath(name);
bool updated = false;
if (QFile::exists(destPath)) {
if (QFile::exists(destPath))
{
// Backup in case install fails
QFile::copy(destPath, destPath + ".bak");
Utils::Fs::forceRemove(destPath);
@@ -237,11 +250,13 @@ void SearchPluginManager::installPlugin_impl(const QString &name, const QString
// Update supported plugins
update();
// Check if this was correctly installed
if (!m_plugins.contains(name)) {
if (!m_plugins.contains(name))
{
// Remove broken file
Utils::Fs::forceRemove(destPath);
LogMsg(tr("Plugin %1 is not supported.").arg(name), Log::INFO);
if (updated) {
if (updated)
{
// restore backup
QFile::copy(destPath + ".bak", destPath);
Utils::Fs::forceRemove(destPath + ".bak");
@@ -249,13 +264,16 @@ void SearchPluginManager::installPlugin_impl(const QString &name, const QString
update();
emit pluginUpdateFailed(name, tr("Plugin is not supported."));
}
else {
else
{
emit pluginInstallationFailed(name, tr("Plugin is not supported."));
}
}
else {
else
{
// Install was successful, remove backup
if (updated) {
if (updated)
{
LogMsg(tr("Plugin %1 has been successfully updated.").arg(name), Log::INFO);
Utils::Fs::forceRemove(destPath + ".bak");
}
@@ -284,10 +302,12 @@ void SearchPluginManager::updateIconPath(PluginInfo *const plugin)
{
if (!plugin) return;
QString iconPath = QString::fromLatin1("%1/%2.png").arg(pluginsLocation(), plugin->name);
if (QFile::exists(iconPath)) {
if (QFile::exists(iconPath))
{
plugin->iconPath = iconPath;
}
else {
else
{
iconPath = QString::fromLatin1("%1/%2.ico").arg(pluginsLocation(), plugin->name);
if (QFile::exists(iconPath))
plugin->iconPath = iconPath;
@@ -317,7 +337,8 @@ SearchHandler *SearchPluginManager::startSearch(const QString &pattern, const QS
QString SearchPluginManager::categoryFullName(const QString &categoryName)
{
const QHash<QString, QString> categoryTable {
const QHash<QString, QString> categoryTable
{
{"all", tr("All categories")},
{"movies", tr("Movies")},
{"tv", tr("TV shows")},
@@ -344,7 +365,8 @@ QString SearchPluginManager::pluginsLocation()
QString SearchPluginManager::engineLocation()
{
static QString location;
if (location.isEmpty()) {
if (location.isEmpty())
{
location = Utils::Fs::expandPathAbs(specialFolderLocation(SpecialFolder::Data) + "nova3");
const QDir locationDir(location);
@@ -364,7 +386,8 @@ void SearchPluginManager::versionInfoDownloadFinished(const Net::DownloadResult
void SearchPluginManager::pluginDownloadFinished(const Net::DownloadResult &result)
{
if (result.status == Net::DownloadStatus::Success) {
if (result.status == Net::DownloadStatus::Success)
{
const QString filePath = Utils::Fs::toUniformPath(result.filePath);
QString pluginName = Utils::Fs::fileName(result.url);
@@ -372,7 +395,8 @@ void SearchPluginManager::pluginDownloadFinished(const Net::DownloadResult &resu
installPlugin_impl(pluginName, filePath);
Utils::Fs::forceRemove(filePath);
}
else {
else
{
const QString url = result.url;
QString pluginName = url.mid(url.lastIndexOf('/') + 1);
pluginName.replace(".py", "", Qt::CaseInsensitive);
@@ -432,21 +456,25 @@ void SearchPluginManager::update()
const QString capabilities = nova.readAll();
QDomDocument xmlDoc;
if (!xmlDoc.setContent(capabilities)) {
if (!xmlDoc.setContent(capabilities))
{
qWarning() << "Could not parse Nova search engine capabilities, msg: " << capabilities.toLocal8Bit().data();
qWarning() << "Error: " << nova.readAllStandardError().constData();
return;
}
const QDomElement root = xmlDoc.documentElement();
if (root.tagName() != "capabilities") {
if (root.tagName() != "capabilities")
{
qWarning() << "Invalid XML file for Nova search engine capabilities, msg: " << capabilities.toLocal8Bit().data();
return;
}
for (QDomNode engineNode = root.firstChild(); !engineNode.isNull(); engineNode = engineNode.nextSibling()) {
for (QDomNode engineNode = root.firstChild(); !engineNode.isNull(); engineNode = engineNode.nextSibling())
{
const QDomElement engineElem = engineNode.toElement();
if (!engineElem.isNull()) {
if (!engineElem.isNull())
{
const QString pluginName = engineElem.tagName();
auto plugin = std::make_unique<PluginInfo>();
@@ -456,7 +484,8 @@ void SearchPluginManager::update()
plugin->url = engineElem.elementsByTagName("url").at(0).toElement().text();
const QStringList categories = engineElem.elementsByTagName("categories").at(0).toElement().text().split(' ');
for (QString cat : categories) {
for (QString cat : categories)
{
cat = cat.trimmed();
if (!cat.isEmpty())
plugin->supportedCategories << cat;
@@ -467,11 +496,13 @@ void SearchPluginManager::update()
updateIconPath(plugin.get());
if (!m_plugins.contains(pluginName)) {
if (!m_plugins.contains(pluginName))
{
m_plugins[pluginName] = plugin.release();
emit pluginInstalled(pluginName);
}
else if (m_plugins[pluginName]->version != plugin->version) {
else if (m_plugins[pluginName]->version != plugin->version)
{
delete m_plugins.take(pluginName);
m_plugins[pluginName] = plugin.release();
emit pluginUpdated(pluginName);
@@ -486,7 +517,8 @@ void SearchPluginManager::parseVersionInfo(const QByteArray &info)
int numCorrectData = 0;
const QVector<QByteArray> lines = Utils::ByteArray::splitToViews(info, "\n", QString::SkipEmptyParts);
for (QByteArray line : lines) {
for (QByteArray line : lines)
{
line = line.trimmed();
if (line.isEmpty()) continue;
if (line.startsWith('#')) continue;
@@ -500,17 +532,20 @@ void SearchPluginManager::parseVersionInfo(const QByteArray &info)
if (!version.isValid()) continue;
++numCorrectData;
if (isUpdateNeeded(pluginName, version)) {
if (isUpdateNeeded(pluginName, version))
{
LogMsg(tr("Plugin \"%1\" is outdated, updating to version %2").arg(pluginName, version), Log::INFO);
updateInfo[pluginName] = version;
}
}
if (numCorrectData < lines.size()) {
if (numCorrectData < lines.size())
{
emit checkForUpdatesFailed(tr("Incorrect update info received for %1 out of %2 plugins.")
.arg(QString::number(lines.size() - numCorrectData), QString::number(lines.size())));
}
else {
else
{
emit checkForUpdatesFinished(updateInfo);
}
}
@@ -535,7 +570,8 @@ PluginVersion SearchPluginManager::getPluginVersion(const QString &filePath)
if (!pluginFile.open(QIODevice::ReadOnly | QIODevice::Text))
return {};
while (!pluginFile.atEnd()) {
while (!pluginFile.atEnd())
{
const QString line = QString(pluginFile.readLine()).remove(' ');
if (!line.startsWith("#VERSION:", Qt::CaseInsensitive)) continue;

View File

@@ -67,7 +67,8 @@ namespace
QString mapKey(const QString &key)
{
static const QHash<QString, QString> keyMapping = {
static const QHash<QString, QString> keyMapping =
{
{"BitTorrent/Session/MaxRatioAction", "Preferences/Bittorrent/MaxRatioAction"},
{"BitTorrent/Session/DefaultSavePath", "Preferences/Downloads/SavePath"},
{"BitTorrent/Session/TempPath", "Preferences/Downloads/TempPath"},
@@ -189,7 +190,8 @@ bool SettingsStorage::save()
if (!m_dirty) return true; // something might have changed while we were getting the lock
const TransactionalSettings settings(QLatin1String("qBittorrent"));
if (!settings.write(m_data)) {
if (!settings.write(m_data))
{
m_timer.start();
return false;
}
@@ -211,7 +213,8 @@ void SettingsStorage::storeValue(const QString &key, const QVariant &value)
const QWriteLocker locker(&m_lock);
QVariant &currentValue = m_data[realKey];
if (currentValue != value) {
if (currentValue != value)
{
m_dirty = true;
currentValue = value;
m_timer.start();
@@ -222,7 +225,8 @@ void SettingsStorage::removeValue(const QString &key)
{
const QString realKey = mapKey(key);
const QWriteLocker locker(&m_lock);
if (m_data.remove(realKey) > 0) {
if (m_data.remove(realKey) > 0)
{
m_dirty = true;
m_timer.start();
}
@@ -233,7 +237,8 @@ QVariantHash TransactionalSettings::read() const
QVariantHash res;
const QString newPath = deserialize(m_name + QLatin1String("_new"), res);
if (!newPath.isEmpty()) { // "_new" file is NOT empty
if (!newPath.isEmpty())
{ // "_new" file is NOT empty
// This means that the PC closed either due to power outage
// or because the disk was full. In any case the settings weren't transferred
// in their final position. So assume that qbittorrent_new.ini/qbittorrent_new.conf
@@ -249,7 +254,8 @@ QVariantHash TransactionalSettings::read() const
Utils::Fs::forceRemove(finalPath);
QFile::rename(newPath, finalPath);
}
else {
else
{
deserialize(m_name, res);
}
@@ -264,7 +270,8 @@ bool TransactionalSettings::write(const QVariantHash &data) const
// Write everything to qBittorrent_new.ini/qBittorrent_new.conf and if it succeeds
// replace qBittorrent.ini/qBittorrent.conf with it.
const QString newPath = serialize(m_name + QLatin1String("_new"), data);
if (newPath.isEmpty()) {
if (newPath.isEmpty())
{
Utils::Fs::forceRemove(newPath);
return false;
}
@@ -301,7 +308,8 @@ QString TransactionalSettings::serialize(const QString &name, const QVariantHash
settings->sync(); // Important to get error status
switch (settings->status()) {
switch (settings->status())
{
case QSettings::NoError:
return settings->fileName();
case QSettings::AccessError:

View File

@@ -73,7 +73,8 @@ TorrentFilter::TorrentFilter(const QString &filter, const QStringSet &hashSet, c
bool TorrentFilter::setType(Type type)
{
if (m_type != type) {
if (m_type != type)
{
m_type = type;
return true;
}
@@ -113,7 +114,8 @@ bool TorrentFilter::setTypeByName(const QString &filter)
bool TorrentFilter::setHashSet(const QStringSet &hashSet)
{
if (m_hashSet != hashSet) {
if (m_hashSet != hashSet)
{
m_hashSet = hashSet;
return true;
}
@@ -126,7 +128,8 @@ bool TorrentFilter::setCategory(const QString &category)
// QString::operator==() doesn't distinguish between empty and null strings.
if ((m_category != category)
|| (m_category.isNull() && !category.isNull())
|| (!m_category.isNull() && category.isNull())) {
|| (!m_category.isNull() && category.isNull()))
{
m_category = category;
return true;
}
@@ -139,7 +142,8 @@ bool TorrentFilter::setTag(const QString &tag)
// QString::operator==() doesn't distinguish between empty and null strings.
if ((m_tag != tag)
|| (m_tag.isNull() && !tag.isNull())
|| (!m_tag.isNull() && tag.isNull())) {
|| (!m_tag.isNull() && tag.isNull()))
{
m_tag = tag;
return true;
}
@@ -156,7 +160,8 @@ bool TorrentFilter::match(const TorrentHandle *const torrent) const
bool TorrentFilter::matchState(const BitTorrent::TorrentHandle *const torrent) const
{
switch (m_type) {
switch (m_type)
{
case All:
return true;
case Downloading:

View File

@@ -40,7 +40,8 @@ QVector<QByteArray> Utils::ByteArray::splitToViews(const QByteArray &in, const Q
? (1 + (in.size() / sep.size()))
: (1 + (in.size() / (sep.size() + 1))));
int head = 0;
while (head < in.size()) {
while (head < in.size())
{
int end = in.indexOf(sep, head);
if (end < 0)
end = in.size();

View File

@@ -53,7 +53,8 @@ namespace
{
QProcess proc;
proc.start(exeName, {"--version"}, QIODevice::ReadOnly);
if (proc.waitForFinished() && (proc.exitCode() == QProcess::NormalExit)) {
if (proc.waitForFinished() && (proc.exitCode() == QProcess::NormalExit))
{
QByteArray procOutput = proc.readAllStandardOutput();
if (procOutput.isEmpty())
procOutput = proc.readAllStandardError();
@@ -71,10 +72,12 @@ namespace
const QString versionStr = outputSplit[1];
const int idx = versionStr.indexOf(QRegularExpression("[^\\.\\d]"));
try {
try
{
info = {exeName, versionStr.left(idx)};
}
catch (const std::runtime_error &) {
catch (const std::runtime_error &)
{
return false;
}
@@ -102,12 +105,14 @@ namespace
DWORD cMaxSubKeyLen = 0;
LONG res = ::RegQueryInfoKeyW(handle, NULL, NULL, NULL, &cSubKeys, &cMaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
if (res == ERROR_SUCCESS) {
if (res == ERROR_SUCCESS)
{
++cMaxSubKeyLen; // For null character
LPWSTR lpName = new WCHAR[cMaxSubKeyLen];
DWORD cName;
for (DWORD i = 0; i < cSubKeys; ++i) {
for (DWORD i = 0; i < cSubKeys; ++i)
{
cName = cMaxSubKeyLen;
res = ::RegEnumKeyExW(handle, i, lpName, &cName, NULL, NULL, NULL, NULL);
if (res == ERROR_SUCCESS)
@@ -127,7 +132,8 @@ namespace
DWORD type = 0;
DWORD cbData = 0;
LPWSTR lpValueName = NULL;
if (!name.isEmpty()) {
if (!name.isEmpty())
{
lpValueName = new WCHAR[name.size() + 1];
name.toWCharArray(lpValueName);
lpValueName[name.size()] = 0;
@@ -141,7 +147,8 @@ namespace
if (lpValueName)
delete[] lpValueName;
if (res == ERROR_SUCCESS) {
if (res == ERROR_SUCCESS)
{
lpData[cBuffer - 1] = 0;
result = QString::fromWCharArray(lpData);
}
@@ -169,13 +176,15 @@ namespace
HKEY hkPythonCore;
res = ::RegOpenKeyExW(hkRoot, L"SOFTWARE\\Python\\PythonCore", 0, samDesired, &hkPythonCore);
if (res == ERROR_SUCCESS) {
if (res == ERROR_SUCCESS)
{
QStringList versions = getRegSubkeys(hkPythonCore);
qDebug("Python versions nb: %d", versions.size());
versions.sort();
bool found = false;
while (!found && !versions.empty()) {
while (!found && !versions.empty())
{
const QString version = versions.takeLast() + "\\InstallPath";
LPWSTR lpSubkey = new WCHAR[version.size() + 1];
version.toWCharArray(lpSubkey);
@@ -185,19 +194,23 @@ namespace
res = ::RegOpenKeyExW(hkPythonCore, lpSubkey, 0, samDesired, &hkInstallPath);
delete[] lpSubkey;
if (res == ERROR_SUCCESS) {
if (res == ERROR_SUCCESS)
{
qDebug("Detected possible Python v%s location", qUtf8Printable(version));
path = getRegValue(hkInstallPath);
::RegCloseKey(hkInstallPath);
if (!path.isEmpty()) {
if (!path.isEmpty())
{
const QDir baseDir {path};
if (baseDir.exists("python3.exe")) {
if (baseDir.exists("python3.exe"))
{
found = true;
path = baseDir.filePath("python3.exe");
}
else if (baseDir.exists("python.exe")) {
else if (baseDir.exists("python.exe"))
{
found = true;
path = baseDir.filePath("python.exe");
}
@@ -230,7 +243,8 @@ namespace
// Fallback: Detect python from default locations
const QFileInfoList dirs = QDir("C:/").entryInfoList({"Python*"}, QDir::Dirs, (QDir::Name | QDir::Reversed));
for (const QFileInfo &info : dirs) {
for (const QFileInfo &info : dirs)
{
const QString py3Path {info.absolutePath() + "/python3.exe"};
if (QFile::exists(py3Path))
return py3Path;
@@ -258,7 +272,8 @@ bool Utils::ForeignApps::PythonInfo::isSupportedVersion() const
PythonInfo Utils::ForeignApps::pythonInfo()
{
static PythonInfo pyInfo;
if (!pyInfo.isValid()) {
if (!pyInfo.isValid())
{
if (testPythonInstallation("python3", pyInfo))
return pyInfo;

View File

@@ -113,7 +113,8 @@ bool Utils::Fs::smartRemoveEmptyFolderTree(const QString &path)
if (path.isEmpty() || !QDir(path).exists())
return true;
const QStringList deleteFilesList = {
const QStringList deleteFilesList =
{
// Windows
QLatin1String("Thumbs.db"),
QLatin1String("desktop.ini"),
@@ -132,7 +133,8 @@ bool Utils::Fs::smartRemoveEmptyFolderTree(const QString &path)
std::sort(dirList.begin(), dirList.end()
, [](const QString &l, const QString &r) { return l.count('/') > r.count('/'); });
for (const QString &p : asConst(dirList)) {
for (const QString &p : asConst(dirList))
{
const QDir dir(p);
// A deeper folder may have not been removed in the previous iteration
// so don't remove anything from this folder either.
@@ -201,7 +203,8 @@ qint64 Utils::Fs::computePathSize(const QString &path)
// Compute folder size based on its content
qint64 size = 0;
QDirIterator iter(path, QDir::Files | QDir::Hidden | QDir::NoSymLinks, QDirIterator::Subdirectories);
while (iter.hasNext()) {
while (iter.hasNext())
{
iter.next();
size += iter.fileInfo().size();
}
@@ -220,7 +223,8 @@ bool Utils::Fs::sameFiles(const QString &path1, const QString &path2)
if (!f2.open(QIODevice::ReadOnly)) return false;
const int readSize = 1024 * 1024; // 1 MiB
while (!f1.atEnd() && !f2.atEnd()) {
while (!f1.atEnd() && !f2.atEnd())
{
if (f1.read(readSize) != f2.read(readSize))
return false;
}
@@ -243,15 +247,18 @@ bool Utils::Fs::isValidFileSystemName(const QString &name, const bool allowSepar
if (name.isEmpty()) return false;
#if defined(Q_OS_WIN)
const QRegularExpression regex {allowSeparators
const QRegularExpression regex
{allowSeparators
? QLatin1String("[:?\"*<>|]")
: QLatin1String("[\\\\/:?\"*<>|]")};
#elif defined(Q_OS_MACOS)
const QRegularExpression regex {allowSeparators
const QRegularExpression regex
{allowSeparators
? QLatin1String("[\\0:]")
: QLatin1String("[\\0/:]")};
#else
const QRegularExpression regex {allowSeparators
const QRegularExpression regex
{allowSeparators
? QLatin1String("[\\0]")
: QLatin1String("[\\0/]")};
#endif
@@ -271,7 +278,8 @@ QString Utils::Fs::branchPath(const QString &filePath, QString *removed)
if (ret.endsWith('/'))
ret.chop(1);
const int slashIndex = ret.lastIndexOf('/');
if (slashIndex >= 0) {
if (slashIndex >= 0)
{
if (removed)
*removed = ret.mid(slashIndex + 1);
ret = ret.left(slashIndex);
@@ -312,7 +320,8 @@ QString Utils::Fs::tempPath()
bool Utils::Fs::isRegularFile(const QString &path)
{
struct ::stat st;
if (::stat(path.toUtf8().constData(), &st) != 0) {
if (::stat(path.toUtf8().constData(), &st) != 0)
{
// analyse erno and log the error
const auto err = errno;
qDebug("Could not get file stats for path '%s'. Error: %s"
@@ -360,7 +369,8 @@ bool Utils::Fs::isNetworkFileSystem(const QString &path)
// Magic number references:
// 1. /usr/include/linux/magic.h
// 2. https://github.com/coreutils/coreutils/blob/master/src/stat.c
switch (static_cast<unsigned int>(buf.f_type)) {
switch (static_cast<unsigned int>(buf.f_type))
{
case 0xFF534D42: // CIFS_MAGIC_NUMBER
case 0x6969: // NFS_SUPER_MAGIC
case 0x517B: // SMB_SUPER_MAGIC

View File

@@ -68,10 +68,12 @@ QByteArray Utils::Gzip::compress(const QByteArray &data, const int level, bool *
output.reserve(deflateBound(&strm, data.size()));
// feed to deflate
while (strm.avail_in > 0) {
while (strm.avail_in > 0)
{
result = deflate(&strm, Z_NO_FLUSH);
if (result != Z_OK) {
if (result != Z_OK)
{
deflateEnd(&strm);
return {};
}
@@ -82,7 +84,8 @@ QByteArray Utils::Gzip::compress(const QByteArray &data, const int level, bool *
}
// flush the rest from deflate
while (result != Z_STREAM_END) {
while (result != Z_STREAM_END)
{
result = deflate(&strm, Z_FINISH);
output.append(tmpBuf.data(), (BUFSIZE - strm.avail_out));
@@ -126,15 +129,18 @@ QByteArray Utils::Gzip::decompress(const QByteArray &data, bool *ok)
output.reserve(data.size() * 3);
// run inflate
while (true) {
while (true)
{
result = inflate(&strm, Z_NO_FLUSH);
if (result == Z_STREAM_END) {
if (result == Z_STREAM_END)
{
output.append(tmpBuf.data(), (BUFSIZE - strm.avail_out));
break;
}
if (result != Z_OK) {
if (result != Z_OK)
{
inflateEnd(&strm);
return {};
}

View File

@@ -41,7 +41,8 @@ Utils::IO::FileDeviceOutputIterator::FileDeviceOutputIterator(QFileDevice &devic
Utils::IO::FileDeviceOutputIterator::~FileDeviceOutputIterator()
{
if (m_buffer.use_count() == 1) {
if (m_buffer.use_count() == 1)
{
if (m_device->error() == QFileDevice::NoError)
m_device->write(*m_buffer);
m_buffer->clear();
@@ -51,7 +52,8 @@ Utils::IO::FileDeviceOutputIterator::~FileDeviceOutputIterator()
Utils::IO::FileDeviceOutputIterator &Utils::IO::FileDeviceOutputIterator::operator=(const char c)
{
m_buffer->append(c);
if (m_buffer->size() >= m_bufferSize) {
if (m_buffer->size() >= m_bufferSize)
{
if (m_device->error() == QFileDevice::NoError)
m_device->write(*m_buffer);
m_buffer->clear();

View File

@@ -63,7 +63,8 @@
namespace
{
const struct { const char *source; const char *comment; } units[] = {
const struct { const char *source; const char *comment; } units[] =
{
QT_TRANSLATE_NOOP3("misc", "B", "bytes"),
QT_TRANSLATE_NOOP3("misc", "KiB", "kibibytes (1024 bytes)"),
QT_TRANSLATE_NOOP3("misc", "MiB", "mebibytes (1024 kibibytes)"),
@@ -85,7 +86,8 @@ namespace
int i = 0;
val = static_cast<qreal>(sizeInBytes);
while ((val >= 1024.) && (i <= static_cast<int>(Utils::Misc::SizeUnit::ExbiByte))) {
while ((val >= 1024.) && (i <= static_cast<int>(Utils::Misc::SizeUnit::ExbiByte)))
{
val /= 1024.;
++i;
}
@@ -119,13 +121,16 @@ void Utils::Misc::shutdownComputer(const ShutdownDialogAction &action)
if (GetLastError() != ERROR_SUCCESS)
return;
if (action == ShutdownDialogAction::Suspend) {
if (action == ShutdownDialogAction::Suspend)
{
::SetSuspendState(false, false, false);
}
else if (action == ShutdownDialogAction::Hibernate) {
else if (action == ShutdownDialogAction::Hibernate)
{
::SetSuspendState(true, false, false);
}
else {
else
{
const QString msg = QCoreApplication::translate("misc", "qBittorrent will shutdown the computer now because all downloads are complete.");
auto msgWchar = std::make_unique<wchar_t[]>(msg.length() + 1);
msg.toWCharArray(msgWchar.get());
@@ -171,11 +176,13 @@ void Utils::Misc::shutdownComputer(const ShutdownDialogAction &action)
#elif (defined(Q_OS_UNIX) && defined(QT_DBUS_LIB))
// Use dbus to power off / suspend the system
if (action != ShutdownDialogAction::Shutdown) {
if (action != ShutdownDialogAction::Shutdown)
{
// Some recent systems use systemd's logind
QDBusInterface login1Iface("org.freedesktop.login1", "/org/freedesktop/login1",
"org.freedesktop.login1.Manager", QDBusConnection::systemBus());
if (login1Iface.isValid()) {
if (login1Iface.isValid())
{
if (action == ShutdownDialogAction::Suspend)
login1Iface.call("Suspend", false);
else
@@ -185,7 +192,8 @@ void Utils::Misc::shutdownComputer(const ShutdownDialogAction &action)
// Else, other recent systems use UPower
QDBusInterface upowerIface("org.freedesktop.UPower", "/org/freedesktop/UPower",
"org.freedesktop.UPower", QDBusConnection::systemBus());
if (upowerIface.isValid()) {
if (upowerIface.isValid())
{
if (action == ShutdownDialogAction::Suspend)
upowerIface.call("Suspend");
else
@@ -201,18 +209,21 @@ void Utils::Misc::shutdownComputer(const ShutdownDialogAction &action)
else
halIface.call("Hibernate");
}
else {
else
{
// Some recent systems use systemd's logind
QDBusInterface login1Iface("org.freedesktop.login1", "/org/freedesktop/login1",
"org.freedesktop.login1.Manager", QDBusConnection::systemBus());
if (login1Iface.isValid()) {
if (login1Iface.isValid())
{
login1Iface.call("PowerOff", false);
return;
}
// Else, other recent systems use ConsoleKit
QDBusInterface consolekitIface("org.freedesktop.ConsoleKit", "/org/freedesktop/ConsoleKit/Manager",
"org.freedesktop.ConsoleKit.Manager", QDBusConnection::systemBus());
if (consolekitIface.isValid()) {
if (consolekitIface.isValid())
{
consolekitIface.call("Stop");
return;
}
@@ -251,7 +262,8 @@ QString Utils::Misc::friendlyUnit(const qint64 bytesValue, const bool isSpeed)
int Utils::Misc::friendlyUnitPrecision(const SizeUnit unit)
{
// friendlyUnit's number of digits after the decimal point
switch (unit) {
switch (unit)
{
case SizeUnit::Byte:
return 0;
case SizeUnit::KibiByte:
@@ -273,7 +285,8 @@ qlonglong Utils::Misc::sizeInBytes(qreal size, const Utils::Misc::SizeUnit unit)
bool Utils::Misc::isPreviewable(const QString &extension)
{
static const QSet<QString> multimediaExtensions = {
static const QSet<QString> multimediaExtensions =
{
"3GP",
"AAC",
"AC3",
@@ -338,13 +351,15 @@ QString Utils::Misc::userFriendlyDuration(const qlonglong seconds, const qlonglo
return QCoreApplication::translate("misc", "%1m", "e.g: 10minutes").arg(QString::number(minutes));
qlonglong hours = (minutes / 60);
if (hours < 24) {
if (hours < 24)
{
minutes -= (hours * 60);
return QCoreApplication::translate("misc", "%1h %2m", "e.g: 3hours 5minutes").arg(QString::number(hours), QString::number(minutes));
}
qlonglong days = (hours / 24);
if (days < 365) {
if (days < 365)
{
hours -= (days * 24);
return QCoreApplication::translate("misc", "%1d %2h", "e.g: 2days 10hours").arg(QString::number(days), QString::number(hours));
}
@@ -479,7 +494,8 @@ QString Utils::Misc::zlibVersionString()
#ifdef Q_OS_WIN
QString Utils::Misc::windowsSystemPath()
{
static const QString path = []() -> QString {
static const QString path = []() -> QString
{
WCHAR systemPath[MAX_PATH] = {0};
GetSystemDirectoryW(systemPath, sizeof(systemPath) / sizeof(WCHAR));
return QString::fromWCharArray(systemPath);

View File

@@ -70,12 +70,14 @@ namespace Utils
QHostAddress protocolEquivalentAddress;
bool addrConversionOk = false;
if (addr.protocol() == QAbstractSocket::IPv4Protocol) {
if (addr.protocol() == QAbstractSocket::IPv4Protocol)
{
// always succeeds
protocolEquivalentAddress = QHostAddress(addr.toIPv6Address());
addrConversionOk = true;
}
else {
else
{
// only succeeds when addr is an ipv4-mapped ipv6 address
protocolEquivalentAddress = QHostAddress(addr.toIPv4Address(&addrConversionOk));
}

View File

@@ -71,7 +71,8 @@ QByteArray Utils::Password::PBKDF2::generate(const QString &password)
QByteArray Utils::Password::PBKDF2::generate(const QByteArray &password)
{
const std::array<uint32_t, 4> salt {{Random::rand(), Random::rand()
const std::array<uint32_t, 4> salt
{{Random::rand(), Random::rand()
, Random::rand(), Random::rand()}};
std::array<unsigned char, 64> outBuf {};

View File

@@ -82,7 +82,8 @@ namespace
int posL = 0;
int posR = 0;
while (true) {
while (true)
{
if ((posL == left.size()) || (posR == right.size()))
return (left.size() - right.size()); // when a shorter string is another string's prefix, shorter string place before longer string
@@ -91,12 +92,14 @@ namespace
// Compare only non-digits.
// Numbers should be compared as a whole
// otherwise the string->int conversion can yield a wrong value
if ((leftChar == rightChar) && !leftChar.isDigit()) {
if ((leftChar == rightChar) && !leftChar.isDigit())
{
// compare next character
++posL;
++posR;
}
else if (leftChar.isDigit() && rightChar.isDigit()) {
else if (leftChar.isDigit() && rightChar.isDigit())
{
// Both are digits, compare the numbers
const auto numberView = [](const QString &str, int &pos) -> QStringRef
@@ -114,7 +117,8 @@ namespace
return (numViewL.length() - numViewR.length());
// both string/view has the same length
for (int i = 0; i < numViewL.length(); ++i) {
for (int i = 0; i < numViewL.length(); ++i)
{
const QChar numL = numViewL[i];
const QChar numR = numViewR[i];
@@ -125,7 +129,8 @@ namespace
// String + digits do match and we haven't hit the end of both strings
// then continue to consume the remainings
}
else {
else
{
return (leftChar.unicode() - rightChar.unicode());
}
}
@@ -140,7 +145,8 @@ int Utils::String::naturalCompare(const QString &left, const QString &right, con
{
// provide a single `NaturalCompare` instance for easy use
// https://doc.qt.io/qt-5/threads-reentrancy.html
if (caseSensitivity == Qt::CaseSensitive) {
if (caseSensitivity == Qt::CaseSensitive)
{
#ifdef QBT_USES_QTHREADSTORAGE
static QThreadStorage<NaturalCompare> nCmp;
if (!nCmp.hasLocalData())

View File

@@ -58,7 +58,8 @@ namespace Utils
{
if (str.length() < 2) return str;
for (const QChar quote : quotes) {
for (const QChar quote : quotes)
{
if (str.startsWith(quote) && str.endsWith(quote))
return str.mid(1, (str.length() - 2));
}

View File

@@ -151,10 +151,12 @@ namespace Utils
template <typename StringClassWithSplitMethod>
static Version tryParse(const StringClassWithSplitMethod &s, const Version &defaultVersion)
{
try {
try
{
return Version(s);
}
catch (const std::runtime_error &er) {
catch (const std::runtime_error &er)
{
qDebug() << "Error parsing version:" << er.what();
return defaultVersion;
}
@@ -172,7 +174,8 @@ namespace Utils
bool ok = false;
ComponentsArray res {{}};
for (std::size_t i = 0; i < static_cast<std::size_t>(versionParts.size()); ++i) {
for (std::size_t i = 0; i < static_cast<std::size_t>(versionParts.size()); ++i)
{
res[i] = static_cast<T>(versionParts[static_cast<typename StringsList::size_type>(i)].toInt(&ok));
if (!ok)
throw std::runtime_error("Can not parse version component");