mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2026-01-01 05:08:05 -06:00
Improve coding style
This commit is contained in:
@@ -70,7 +70,8 @@ void AppController::versionAction()
|
||||
|
||||
void AppController::buildInfoAction()
|
||||
{
|
||||
const QJsonObject versions = {
|
||||
const QJsonObject versions =
|
||||
{
|
||||
{"qt", QT_VERSION_STR},
|
||||
{"libtorrent", Utils::Misc::libtorrentVersionString()},
|
||||
{"boost", Utils::Misc::boostVersionString()},
|
||||
@@ -117,7 +118,8 @@ void AppController::preferencesAction()
|
||||
// Automatically add torrents from
|
||||
const QVariantHash dirs = pref->getScanDirs();
|
||||
QJsonObject nativeDirs;
|
||||
for (auto i = dirs.cbegin(); i != dirs.cend(); ++i) {
|
||||
for (auto i = dirs.cbegin(); i != dirs.cend(); ++i)
|
||||
{
|
||||
if (i.value().type() == QVariant::Int)
|
||||
nativeDirs.insert(Utils::Fs::toNativePath(i.key()), i.value().toInt());
|
||||
else
|
||||
@@ -383,21 +385,25 @@ void AppController::setPreferencesAction()
|
||||
if (hasKey("export_dir_fin"))
|
||||
session->setFinishedTorrentExportDirectory(it.value().toString());
|
||||
// Automatically add torrents from
|
||||
if (hasKey("scan_dirs")) {
|
||||
if (hasKey("scan_dirs"))
|
||||
{
|
||||
const QVariantHash nativeDirs = it.value().toHash();
|
||||
QVariantHash oldScanDirs = pref->getScanDirs();
|
||||
QVariantHash scanDirs;
|
||||
ScanFoldersModel *model = ScanFoldersModel::instance();
|
||||
for (auto i = nativeDirs.cbegin(); i != nativeDirs.cend(); ++i) {
|
||||
for (auto i = nativeDirs.cbegin(); i != nativeDirs.cend(); ++i)
|
||||
{
|
||||
QString folder = Utils::Fs::toUniformPath(i.key());
|
||||
int downloadType;
|
||||
QString downloadPath;
|
||||
ScanFoldersModel::PathStatus ec;
|
||||
if (i.value().type() == QVariant::String) {
|
||||
if (i.value().type() == QVariant::String)
|
||||
{
|
||||
downloadType = ScanFoldersModel::CUSTOM_LOCATION;
|
||||
downloadPath = Utils::Fs::toUniformPath(i.value().toString());
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
downloadType = i.value().toInt();
|
||||
downloadPath = (downloadType == ScanFoldersModel::DEFAULT_LOCATION) ? "Default folder" : "Watch folder";
|
||||
}
|
||||
@@ -407,19 +413,23 @@ void AppController::setPreferencesAction()
|
||||
else
|
||||
ec = model->updatePath(folder, static_cast<ScanFoldersModel::PathType>(downloadType), downloadPath);
|
||||
|
||||
if (ec == ScanFoldersModel::Ok) {
|
||||
if (ec == ScanFoldersModel::Ok)
|
||||
{
|
||||
scanDirs.insert(folder, (downloadType == ScanFoldersModel::CUSTOM_LOCATION) ? QVariant(downloadPath) : QVariant(downloadType));
|
||||
qDebug("New watched folder: %s to %s", qUtf8Printable(folder), qUtf8Printable(downloadPath));
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
qDebug("Watched folder %s failed with error %d", qUtf8Printable(folder), ec);
|
||||
}
|
||||
}
|
||||
|
||||
// Update deleted folders
|
||||
for (auto i = oldScanDirs.cbegin(); i != oldScanDirs.cend(); ++i) {
|
||||
for (auto i = oldScanDirs.cbegin(); i != oldScanDirs.cend(); ++i)
|
||||
{
|
||||
const QString &folder = i.key();
|
||||
if (!scanDirs.contains(folder)) {
|
||||
if (!scanDirs.contains(folder))
|
||||
{
|
||||
model->removePath(folder);
|
||||
qDebug("Removed watched folder %s", qUtf8Printable(folder));
|
||||
}
|
||||
@@ -555,13 +565,15 @@ void AppController::setPreferencesAction()
|
||||
if (hasKey("slow_torrent_inactive_timer"))
|
||||
session->setSlowTorrentsInactivityTimer(it.value().toInt());
|
||||
// Share Ratio Limiting
|
||||
if (hasKey("max_ratio_enabled")) {
|
||||
if (hasKey("max_ratio_enabled"))
|
||||
{
|
||||
if (it.value().toBool())
|
||||
session->setGlobalMaxRatio(m["max_ratio"].toReal());
|
||||
else
|
||||
session->setGlobalMaxRatio(-1);
|
||||
}
|
||||
if (hasKey("max_seeding_time_enabled")) {
|
||||
if (hasKey("max_seeding_time_enabled"))
|
||||
{
|
||||
if (it.value().toBool())
|
||||
session->setGlobalMaxSeedingMinutes(m["max_seeding_time"].toInt());
|
||||
else
|
||||
@@ -577,14 +589,18 @@ void AppController::setPreferencesAction()
|
||||
|
||||
// Web UI
|
||||
// Language
|
||||
if (hasKey("locale")) {
|
||||
if (hasKey("locale"))
|
||||
{
|
||||
QString locale = it.value().toString();
|
||||
if (pref->getLocale() != locale) {
|
||||
if (pref->getLocale() != locale)
|
||||
{
|
||||
auto *translator = new QTranslator;
|
||||
if (translator->load(QLatin1String(":/lang/qbittorrent_") + locale)) {
|
||||
if (translator->load(QLatin1String(":/lang/qbittorrent_") + locale))
|
||||
{
|
||||
qDebug("%s locale recognized, using translation.", qUtf8Printable(locale));
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
qDebug("%s locale unrecognized, using default (en).", qUtf8Printable(locale));
|
||||
}
|
||||
qApp->installTranslator(translator);
|
||||
@@ -616,7 +632,8 @@ void AppController::setPreferencesAction()
|
||||
pref->setWebUiLocalAuthEnabled(!it.value().toBool());
|
||||
if (hasKey("bypass_auth_subnet_whitelist_enabled"))
|
||||
pref->setWebUiAuthSubnetWhitelistEnabled(it.value().toBool());
|
||||
if (hasKey("bypass_auth_subnet_whitelist")) {
|
||||
if (hasKey("bypass_auth_subnet_whitelist"))
|
||||
{
|
||||
// recognize new lines and commas as delimiters
|
||||
pref->setWebUiAuthSubnetWhitelist(it.value().toString().split(QRegularExpression("\n|,"), QString::SkipEmptyParts));
|
||||
}
|
||||
@@ -673,7 +690,8 @@ void AppController::setPreferencesAction()
|
||||
// Advanced settings
|
||||
// qBittorrent preferences
|
||||
// Current network interface
|
||||
if (hasKey("current_network_interface")) {
|
||||
if (hasKey("current_network_interface"))
|
||||
{
|
||||
const QString ifaceValue {it.value().toString()};
|
||||
|
||||
const QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces();
|
||||
@@ -687,7 +705,8 @@ void AppController::setPreferencesAction()
|
||||
session->setNetworkInterfaceName(ifaceName);
|
||||
}
|
||||
// Current network interface address
|
||||
if (hasKey("current_interface_address")) {
|
||||
if (hasKey("current_interface_address"))
|
||||
{
|
||||
const QHostAddress ifaceAddress {it.value().toString().trimmed()};
|
||||
session->setNetworkInterfaceAddress(ifaceAddress.isNull() ? QString {} : ifaceAddress.toString());
|
||||
}
|
||||
@@ -777,7 +796,8 @@ void AppController::setPreferencesAction()
|
||||
session->setAnnounceToAllTrackers(it.value().toBool());
|
||||
if (hasKey("announce_to_all_tiers"))
|
||||
session->setAnnounceToAllTiers(it.value().toBool());
|
||||
if (hasKey("announce_ip")) {
|
||||
if (hasKey("announce_ip"))
|
||||
{
|
||||
const QHostAddress announceAddr {it.value().toString().trimmed()};
|
||||
session->setAnnounceIP(announceAddr.isNull() ? QString {} : announceAddr.toString());
|
||||
}
|
||||
@@ -805,9 +825,12 @@ void AppController::defaultSavePathAction()
|
||||
void AppController::networkInterfaceListAction()
|
||||
{
|
||||
QJsonArray ifaceList;
|
||||
for (const QNetworkInterface &iface : asConst(QNetworkInterface::allInterfaces())) {
|
||||
if (!iface.addressEntries().isEmpty()) {
|
||||
ifaceList.append(QJsonObject {
|
||||
for (const QNetworkInterface &iface : asConst(QNetworkInterface::allInterfaces()))
|
||||
{
|
||||
if (!iface.addressEntries().isEmpty())
|
||||
{
|
||||
ifaceList.append(QJsonObject
|
||||
{
|
||||
{"name", iface.humanReadableName()},
|
||||
{"value", iface.name()}
|
||||
});
|
||||
@@ -832,11 +855,13 @@ void AppController::networkInterfaceAddressListAction()
|
||||
addressList.append(addr.toString());
|
||||
};
|
||||
|
||||
if (ifaceName.isEmpty()) {
|
||||
if (ifaceName.isEmpty())
|
||||
{
|
||||
for (const QHostAddress &addr : asConst(QNetworkInterface::allAddresses()))
|
||||
appendAddress(addr);
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
const QNetworkInterface iface = QNetworkInterface::interfaceFromName(ifaceName);
|
||||
for (const QNetworkAddressEntry &entry : asConst(iface.addressEntries()))
|
||||
appendAddress(entry.ip());
|
||||
|
||||
@@ -38,7 +38,8 @@
|
||||
|
||||
void AuthController::loginAction()
|
||||
{
|
||||
if (sessionManager()->session()) {
|
||||
if (sessionManager()->session())
|
||||
{
|
||||
setResult(QLatin1String("Ok."));
|
||||
return;
|
||||
}
|
||||
@@ -47,7 +48,8 @@ void AuthController::loginAction()
|
||||
const QString usernameFromWeb {params()["username"]};
|
||||
const QString passwordFromWeb {params()["password"]};
|
||||
|
||||
if (isBanned()) {
|
||||
if (isBanned())
|
||||
{
|
||||
LogMsg(tr("WebAPI login failure. Reason: IP has been banned, IP: %1, username: %2")
|
||||
.arg(clientAddr, usernameFromWeb)
|
||||
, Log::WARNING);
|
||||
@@ -62,14 +64,16 @@ void AuthController::loginAction()
|
||||
const bool usernameEqual = Utils::Password::slowEquals(usernameFromWeb.toUtf8(), username.toUtf8());
|
||||
const bool passwordEqual = Utils::Password::PBKDF2::verify(secret, passwordFromWeb);
|
||||
|
||||
if (usernameEqual && passwordEqual) {
|
||||
if (usernameEqual && passwordEqual)
|
||||
{
|
||||
m_clientFailedLogins.remove(clientAddr);
|
||||
|
||||
sessionManager()->sessionStart();
|
||||
setResult(QLatin1String("Ok."));
|
||||
LogMsg(tr("WebAPI login success. IP: %1").arg(clientAddr));
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
if (Preferences::instance()->getWebUIMaxAuthFailCount() > 0)
|
||||
increaseFailedAttempts();
|
||||
setResult(QLatin1String("Fails."));
|
||||
@@ -91,7 +95,8 @@ bool AuthController::isBanned() const
|
||||
return false;
|
||||
|
||||
bool isBanned = (failedLoginIter->banTimer.remainingTime() >= 0);
|
||||
if (isBanned && failedLoginIter->banTimer.hasExpired()) {
|
||||
if (isBanned && failedLoginIter->banTimer.hasExpired())
|
||||
{
|
||||
m_clientFailedLogins.erase(failedLoginIter);
|
||||
isBanned = false;
|
||||
}
|
||||
@@ -111,7 +116,8 @@ void AuthController::increaseFailedAttempts()
|
||||
FailedLogin &failedLogin = m_clientFailedLogins[sessionManager()->clientId()];
|
||||
++failedLogin.failedAttemptsCount;
|
||||
|
||||
if (failedLogin.failedAttemptsCount >= Preferences::instance()->getWebUIMaxAuthFailCount()) {
|
||||
if (failedLogin.failedAttemptsCount >= Preferences::instance()->getWebUIMaxAuthFailCount())
|
||||
{
|
||||
// Max number of failed attempts reached
|
||||
// Start ban period
|
||||
failedLogin.banTimer.setRemainingTime(Preferences::instance()->getWebUIBanDuration());
|
||||
|
||||
@@ -40,7 +40,8 @@ struct ISession
|
||||
virtual void setData(const QString &id, const QVariant &data) = 0;
|
||||
|
||||
template <class T>
|
||||
T getData(const QString &id) const {
|
||||
T getData(const QString &id) const
|
||||
{
|
||||
return this->getData(id).value<T>();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -73,14 +73,16 @@ void LogController::mainAction()
|
||||
Logger *const logger = Logger::instance();
|
||||
QJsonArray msgList;
|
||||
|
||||
for (const Log::Msg &msg : asConst(logger->getMessages(lastKnownId))) {
|
||||
for (const Log::Msg &msg : asConst(logger->getMessages(lastKnownId)))
|
||||
{
|
||||
if (!((msg.type == Log::NORMAL && isNormal)
|
||||
|| (msg.type == Log::INFO && isInfo)
|
||||
|| (msg.type == Log::WARNING && isWarning)
|
||||
|| (msg.type == Log::CRITICAL && isCritical)))
|
||||
continue;
|
||||
|
||||
msgList.append(QJsonObject {
|
||||
msgList.append(QJsonObject
|
||||
{
|
||||
{KEY_LOG_ID, msg.id},
|
||||
{KEY_LOG_TIMESTAMP, msg.timestamp},
|
||||
{KEY_LOG_MSG_TYPE, msg.type},
|
||||
@@ -113,8 +115,10 @@ void LogController::peersAction()
|
||||
Logger *const logger = Logger::instance();
|
||||
QJsonArray peerList;
|
||||
|
||||
for (const Log::Peer &peer : asConst(logger->getPeers(lastKnownId))) {
|
||||
peerList.append(QJsonObject {
|
||||
for (const Log::Peer &peer : asConst(logger->getPeers(lastKnownId)))
|
||||
{
|
||||
peerList.append(QJsonObject
|
||||
{
|
||||
{KEY_LOG_ID, peer.id},
|
||||
{KEY_LOG_TIMESTAMP, peer.timestamp},
|
||||
{KEY_LOG_PEER_IP, peer.ip},
|
||||
|
||||
@@ -104,15 +104,18 @@ void RSSController::markAsReadAction()
|
||||
RSS::Item *item = RSS::Session::instance()->itemByPath(itemPath);
|
||||
if (!item) return;
|
||||
|
||||
if (!articleId.isNull()) {
|
||||
if (!articleId.isNull())
|
||||
{
|
||||
RSS::Feed *feed = qobject_cast<RSS::Feed *>(item);
|
||||
if (feed) {
|
||||
if (feed)
|
||||
{
|
||||
RSS::Article *article = feed->articleByGUID(articleId);
|
||||
if (article)
|
||||
article->markAsRead();
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
item->markAsRead();
|
||||
}
|
||||
}
|
||||
@@ -174,12 +177,14 @@ void RSSController::matchingArticlesAction()
|
||||
const RSS::AutoDownloadRule rule = RSS::AutoDownloader::instance()->ruleByName(ruleName);
|
||||
|
||||
QJsonObject jsonObj;
|
||||
for (const QString &feedURL : rule.feedURLs()) {
|
||||
for (const QString &feedURL : rule.feedURLs())
|
||||
{
|
||||
const RSS::Feed *feed = RSS::Session::instance()->feedByURL(feedURL);
|
||||
if (!feed) continue; // feed doesn't exist
|
||||
|
||||
QJsonArray matchingArticles;
|
||||
for (const RSS::Article *article : feed->articles()) {
|
||||
for (const RSS::Article *article : feed->articles())
|
||||
{
|
||||
if (rule.matches(article->data()))
|
||||
matchingArticles << article->title();
|
||||
}
|
||||
|
||||
@@ -68,14 +68,17 @@ namespace
|
||||
*/
|
||||
QJsonArray getPluginCategories(QStringList categories)
|
||||
{
|
||||
QJsonArray categoriesInfo {QJsonObject {
|
||||
QJsonArray categoriesInfo
|
||||
{QJsonObject {
|
||||
{QLatin1String("id"), "all"},
|
||||
{QLatin1String("name"), SearchPluginManager::categoryFullName("all")}
|
||||
}};
|
||||
|
||||
categories.sort(Qt::CaseInsensitive);
|
||||
for (const QString &category : categories) {
|
||||
categoriesInfo << QJsonObject {
|
||||
for (const QString &category : categories)
|
||||
{
|
||||
categoriesInfo << QJsonObject
|
||||
{
|
||||
{QLatin1String("id"), category},
|
||||
{QLatin1String("name"), SearchPluginManager::categoryFullName(category)}
|
||||
};
|
||||
@@ -97,7 +100,8 @@ void SearchController::startAction()
|
||||
const QStringList plugins = params()["plugins"].split('|');
|
||||
|
||||
QStringList pluginsToUse;
|
||||
if (plugins.size() == 1) {
|
||||
if (plugins.size() == 1)
|
||||
{
|
||||
const QString pluginsLower = plugins[0].toLower();
|
||||
if (pluginsLower == "all")
|
||||
pluginsToUse = SearchPluginManager::instance()->allPlugins();
|
||||
@@ -106,7 +110,8 @@ void SearchController::startAction()
|
||||
else
|
||||
pluginsToUse << plugins;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
pluginsToUse << plugins;
|
||||
}
|
||||
|
||||
@@ -144,7 +149,8 @@ void SearchController::stopAction()
|
||||
|
||||
const SearchHandlerPtr searchHandler = searchHandlers[id];
|
||||
|
||||
if (searchHandler->isActive()) {
|
||||
if (searchHandler->isActive())
|
||||
{
|
||||
searchHandler->cancelSearch();
|
||||
removeActiveSearch(session, id);
|
||||
}
|
||||
@@ -161,9 +167,11 @@ void SearchController::statusAction()
|
||||
QJsonArray statusArray;
|
||||
const QList<int> searchIds {(id == 0) ? searchHandlers.keys() : QList<int> {id}};
|
||||
|
||||
for (const int searchId : searchIds) {
|
||||
for (const int searchId : searchIds)
|
||||
{
|
||||
const SearchHandlerPtr searchHandler = searchHandlers[searchId];
|
||||
statusArray << QJsonObject {
|
||||
statusArray << QJsonObject
|
||||
{
|
||||
{"id", searchId},
|
||||
{"status", searchHandler->isActive() ? "Running" : "Stopped"},
|
||||
{"total", searchHandler->results().size()}
|
||||
@@ -271,7 +279,8 @@ void SearchController::updatePluginsAction()
|
||||
|
||||
void SearchController::checkForUpdatesFinished(const QHash<QString, PluginVersion> &updateInfo)
|
||||
{
|
||||
if (updateInfo.isEmpty()) {
|
||||
if (updateInfo.isEmpty())
|
||||
{
|
||||
LogMsg(tr("All plugins are already up to date."), Log::INFO);
|
||||
return;
|
||||
}
|
||||
@@ -279,7 +288,8 @@ void SearchController::checkForUpdatesFinished(const QHash<QString, PluginVersio
|
||||
LogMsg(tr("Updating %1 plugins").arg(updateInfo.size()), Log::INFO);
|
||||
|
||||
SearchPluginManager *const pluginManager = SearchPluginManager::instance();
|
||||
for (const QString &pluginName : asConst(updateInfo.keys())) {
|
||||
for (const QString &pluginName : asConst(updateInfo.keys()))
|
||||
{
|
||||
LogMsg(tr("Updating plugin %1").arg(pluginName), Log::INFO);
|
||||
pluginManager->updatePlugin(pluginName);
|
||||
}
|
||||
@@ -328,8 +338,10 @@ int SearchController::generateSearchId() const
|
||||
QJsonObject SearchController::getResults(const QList<SearchResult> &searchResults, const bool isSearchActive, const int totalResults) const
|
||||
{
|
||||
QJsonArray searchResultsArray;
|
||||
for (const SearchResult &searchResult : searchResults) {
|
||||
searchResultsArray << QJsonObject {
|
||||
for (const SearchResult &searchResult : searchResults)
|
||||
{
|
||||
searchResultsArray << QJsonObject
|
||||
{
|
||||
{"fileName", searchResult.fileName},
|
||||
{"fileUrl", searchResult.fileUrl},
|
||||
{"fileSize", searchResult.fileSize},
|
||||
@@ -340,7 +352,8 @@ QJsonObject SearchController::getResults(const QList<SearchResult> &searchResult
|
||||
};
|
||||
}
|
||||
|
||||
const QJsonObject result = {
|
||||
const QJsonObject result =
|
||||
{
|
||||
{"status", isSearchActive ? "Running" : "Stopped"},
|
||||
{"results", searchResultsArray},
|
||||
{"total", totalResults}
|
||||
@@ -366,10 +379,12 @@ QJsonArray SearchController::getPluginsInfo(const QStringList &plugins) const
|
||||
{
|
||||
QJsonArray pluginsArray;
|
||||
|
||||
for (const QString &plugin : plugins) {
|
||||
for (const QString &plugin : plugins)
|
||||
{
|
||||
const PluginInfo *const pluginInfo = SearchPluginManager::instance()->pluginInfo(plugin);
|
||||
|
||||
pluginsArray << QJsonObject {
|
||||
pluginsArray << QJsonObject
|
||||
{
|
||||
{"name", pluginInfo->name},
|
||||
{"version", QString(pluginInfo->version)},
|
||||
{"fullName", pluginInfo->fullName},
|
||||
|
||||
@@ -39,7 +39,8 @@ namespace
|
||||
{
|
||||
QString torrentStateToString(const BitTorrent::TorrentState state)
|
||||
{
|
||||
switch (state) {
|
||||
switch (state)
|
||||
{
|
||||
case BitTorrent::TorrentState::Error:
|
||||
return QLatin1String("error");
|
||||
case BitTorrent::TorrentState::MissingFiles:
|
||||
@@ -82,7 +83,8 @@ namespace
|
||||
|
||||
QVariantMap serialize(const BitTorrent::TorrentHandle &torrent)
|
||||
{
|
||||
QVariantMap ret = {
|
||||
QVariantMap ret =
|
||||
{
|
||||
{KEY_TORRENT_HASH, QString(torrent.hash())},
|
||||
{KEY_TORRENT_NAME, torrent.name()},
|
||||
{KEY_TORRENT_MAGNET_URI, torrent.createMagnetURI()},
|
||||
@@ -134,10 +136,12 @@ QVariantMap serialize(const BitTorrent::TorrentHandle &torrent)
|
||||
const qreal ratio = torrent.realRatio();
|
||||
ret[KEY_TORRENT_RATIO] = (ratio > BitTorrent::TorrentHandle::MAX_RATIO) ? -1 : ratio;
|
||||
|
||||
if (torrent.isPaused() || torrent.isChecking()) {
|
||||
if (torrent.isPaused() || torrent.isChecking())
|
||||
{
|
||||
ret[KEY_TORRENT_LAST_ACTIVITY_TIME] = 0;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
const qint64 dt = (QDateTime::currentDateTime().toSecsSinceEpoch()
|
||||
- torrent.timeSinceActivity());
|
||||
ret[KEY_TORRENT_LAST_ACTIVITY_TIME] = dt;
|
||||
|
||||
@@ -164,20 +164,24 @@ namespace
|
||||
// initialize output variable
|
||||
syncData.clear();
|
||||
|
||||
for (auto i = data.cbegin(); i != data.cend(); ++i) {
|
||||
for (auto i = data.cbegin(); i != data.cend(); ++i)
|
||||
{
|
||||
const QString &key = i.key();
|
||||
const QVariant &value = i.value();
|
||||
QVariantList removedItems;
|
||||
|
||||
switch (static_cast<QMetaType::Type>(value.type())) {
|
||||
case QMetaType::QVariantMap: {
|
||||
switch (static_cast<QMetaType::Type>(value.type()))
|
||||
{
|
||||
case QMetaType::QVariantMap:
|
||||
{
|
||||
QVariantMap map;
|
||||
processMap(prevData[key].toMap(), value.toMap(), map);
|
||||
if (!map.isEmpty())
|
||||
syncData[key] = map;
|
||||
}
|
||||
break;
|
||||
case QMetaType::QVariantHash: {
|
||||
case QMetaType::QVariantHash:
|
||||
{
|
||||
QVariantMap map;
|
||||
processHash(prevData[key].toHash(), value.toHash(), map, removedItems);
|
||||
if (!map.isEmpty())
|
||||
@@ -186,7 +190,8 @@ namespace
|
||||
syncData[key + KEY_SUFFIX_REMOVED] = removedItems;
|
||||
}
|
||||
break;
|
||||
case QMetaType::QVariantList: {
|
||||
case QMetaType::QVariantList:
|
||||
{
|
||||
QVariantList list;
|
||||
processList(prevData[key].toList(), value.toList(), list, removedItems);
|
||||
if (!list.isEmpty())
|
||||
@@ -225,42 +230,52 @@ namespace
|
||||
syncData.clear();
|
||||
removedItems.clear();
|
||||
|
||||
if (prevData.isEmpty()) {
|
||||
if (prevData.isEmpty())
|
||||
{
|
||||
// If list was empty before, then difference is a whole new list.
|
||||
for (auto i = data.cbegin(); i != data.cend(); ++i)
|
||||
syncData[i.key()] = i.value();
|
||||
}
|
||||
else {
|
||||
for (auto i = data.cbegin(); i != data.cend(); ++i) {
|
||||
switch (i.value().type()) {
|
||||
else
|
||||
{
|
||||
for (auto i = data.cbegin(); i != data.cend(); ++i)
|
||||
{
|
||||
switch (i.value().type())
|
||||
{
|
||||
case QVariant::Map:
|
||||
if (!prevData.contains(i.key())) {
|
||||
if (!prevData.contains(i.key()))
|
||||
{
|
||||
// new list item found - append it to syncData
|
||||
syncData[i.key()] = i.value();
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
QVariantMap map;
|
||||
processMap(prevData[i.key()].toMap(), i.value().toMap(), map);
|
||||
// existing list item found - remove it from prevData
|
||||
prevData.remove(i.key());
|
||||
if (!map.isEmpty()) {
|
||||
if (!map.isEmpty())
|
||||
{
|
||||
// changed list item found - append its changes to syncData
|
||||
syncData[i.key()] = map;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QVariant::StringList:
|
||||
if (!prevData.contains(i.key())) {
|
||||
if (!prevData.contains(i.key()))
|
||||
{
|
||||
// new list item found - append it to syncData
|
||||
syncData[i.key()] = i.value();
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
QVariantList list;
|
||||
QVariantList removedList;
|
||||
processList(prevData[i.key()].toList(), i.value().toList(), list, removedList);
|
||||
// existing list item found - remove it from prevData
|
||||
prevData.remove(i.key());
|
||||
if (!list.isEmpty() || !removedList.isEmpty()) {
|
||||
if (!list.isEmpty() || !removedList.isEmpty())
|
||||
{
|
||||
// changed list item found - append entire list to syncData
|
||||
syncData[i.key()] = i.value();
|
||||
}
|
||||
@@ -271,7 +286,8 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
if (!prevData.isEmpty()) {
|
||||
if (!prevData.isEmpty())
|
||||
{
|
||||
// prevData contains only items that are missing now -
|
||||
// put them in removedItems
|
||||
for (auto i = prevData.cbegin(); i != prevData.cend(); ++i)
|
||||
@@ -287,12 +303,15 @@ namespace
|
||||
syncData.clear();
|
||||
removedItems.clear();
|
||||
|
||||
if (prevData.isEmpty()) {
|
||||
if (prevData.isEmpty())
|
||||
{
|
||||
// If list was empty before, then difference is a whole new list.
|
||||
syncData = data;
|
||||
}
|
||||
else {
|
||||
for (const QVariant &item : data) {
|
||||
else
|
||||
{
|
||||
for (const QVariant &item : data)
|
||||
{
|
||||
if (!prevData.contains(item))
|
||||
// new list item found - append it to syncData
|
||||
syncData.append(item);
|
||||
@@ -313,7 +332,8 @@ namespace
|
||||
QVariantMap syncData;
|
||||
bool fullUpdate = true;
|
||||
int lastResponseId = 0;
|
||||
if (acceptedResponseId > 0) {
|
||||
if (acceptedResponseId > 0)
|
||||
{
|
||||
lastResponseId = lastData[KEY_RESPONSE_ID].toInt();
|
||||
|
||||
if (lastResponseId == acceptedResponseId)
|
||||
@@ -321,13 +341,15 @@ namespace
|
||||
|
||||
int lastAcceptedResponseId = lastAcceptedData[KEY_RESPONSE_ID].toInt();
|
||||
|
||||
if (lastAcceptedResponseId == acceptedResponseId) {
|
||||
if (lastAcceptedResponseId == acceptedResponseId)
|
||||
{
|
||||
processMap(lastAcceptedData, data, syncData);
|
||||
fullUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (fullUpdate) {
|
||||
if (fullUpdate)
|
||||
{
|
||||
lastAcceptedData.clear();
|
||||
syncData = data;
|
||||
syncData[KEY_FULL_UPDATE] = true;
|
||||
@@ -436,7 +458,8 @@ void SyncController::maindataAction()
|
||||
|
||||
QVariantHash torrents;
|
||||
QHash<QString, QStringList> trackers;
|
||||
for (const BitTorrent::TorrentHandle *torrent : asConst(session->torrents())) {
|
||||
for (const BitTorrent::TorrentHandle *torrent : asConst(session->torrents()))
|
||||
{
|
||||
const BitTorrent::InfoHash torrentHash = torrent->hash();
|
||||
|
||||
QVariantMap map = serialize(*torrent);
|
||||
@@ -445,15 +468,18 @@ void SyncController::maindataAction()
|
||||
// Calculated last activity time can differ from actual value by up to 10 seconds (this is a libtorrent issue).
|
||||
// So we don't need unnecessary updates of last activity time in response.
|
||||
const auto iterTorrents = lastResponse.find("torrents");
|
||||
if (iterTorrents != lastResponse.end()) {
|
||||
if (iterTorrents != lastResponse.end())
|
||||
{
|
||||
const QVariantHash lastResponseTorrents = iterTorrents->toHash();
|
||||
const auto iterHash = lastResponseTorrents.find(torrentHash);
|
||||
|
||||
if (iterHash != lastResponseTorrents.end()) {
|
||||
if (iterHash != lastResponseTorrents.end())
|
||||
{
|
||||
const QVariantMap torrentData = iterHash->toMap();
|
||||
const auto iterLastActivity = torrentData.find(KEY_TORRENT_LAST_ACTIVITY_TIME);
|
||||
|
||||
if (iterLastActivity != torrentData.end()) {
|
||||
if (iterLastActivity != torrentData.end())
|
||||
{
|
||||
const int lastValue = iterLastActivity->toInt();
|
||||
if (qAbs(lastValue - map[KEY_TORRENT_LAST_ACTIVITY_TIME].toInt()) < 15)
|
||||
map[KEY_TORRENT_LAST_ACTIVITY_TIME] = lastValue;
|
||||
@@ -470,9 +496,11 @@ void SyncController::maindataAction()
|
||||
|
||||
QVariantHash categories;
|
||||
const QStringMap categoriesList = session->categories();
|
||||
for (auto it = categoriesList.cbegin(); it != categoriesList.cend(); ++it) {
|
||||
for (auto it = categoriesList.cbegin(); it != categoriesList.cend(); ++it)
|
||||
{
|
||||
const QString &key = it.key();
|
||||
categories[key] = QVariantMap {
|
||||
categories[key] = QVariantMap
|
||||
{
|
||||
{"name", key},
|
||||
{"savePath", it.value()}
|
||||
};
|
||||
@@ -485,7 +513,8 @@ void SyncController::maindataAction()
|
||||
data["tags"] = tags;
|
||||
|
||||
QVariantHash trackersHash;
|
||||
for (auto i = trackers.constBegin(); i != trackers.constEnd(); ++i) {
|
||||
for (auto i = trackers.constBegin(); i != trackers.constEnd(); ++i)
|
||||
{
|
||||
trackersHash[i.key()] = i.value();
|
||||
}
|
||||
data["trackers"] = trackersHash;
|
||||
@@ -526,10 +555,12 @@ void SyncController::torrentPeersAction()
|
||||
|
||||
data[KEY_SYNC_TORRENT_PEERS_SHOW_FLAGS] = resolvePeerCountries;
|
||||
|
||||
for (const BitTorrent::PeerInfo &pi : peersList) {
|
||||
for (const BitTorrent::PeerInfo &pi : peersList)
|
||||
{
|
||||
if (pi.address().ip.isNull()) continue;
|
||||
|
||||
QVariantMap peer = {
|
||||
QVariantMap peer =
|
||||
{
|
||||
{KEY_PEER_IP, pi.address().ip.toString()},
|
||||
{KEY_PEER_PORT, pi.address().port},
|
||||
{KEY_PEER_CLIENT, pi.client()},
|
||||
@@ -545,7 +576,8 @@ void SyncController::torrentPeersAction()
|
||||
{KEY_PEER_FILES, torrent->info().filesForPiece(pi.downloadingPieceIndex()).join('\n')}
|
||||
};
|
||||
|
||||
if (resolvePeerCountries) {
|
||||
if (resolvePeerCountries)
|
||||
{
|
||||
peer[KEY_PEER_COUNTRY_CODE] = pi.country().toLower();
|
||||
peer[KEY_PEER_COUNTRY] = Net::GeoIPManager::CountryName(pi.country());
|
||||
}
|
||||
@@ -563,7 +595,8 @@ void SyncController::torrentPeersAction()
|
||||
|
||||
qint64 SyncController::getFreeDiskSpace()
|
||||
{
|
||||
if (m_freeDiskSpaceElapsedTimer.hasExpired(FREEDISKSPACE_CHECK_TIMEOUT)) {
|
||||
if (m_freeDiskSpaceElapsedTimer.hasExpired(FREEDISKSPACE_CHECK_TIMEOUT))
|
||||
{
|
||||
invokeChecker();
|
||||
m_freeDiskSpaceElapsedTimer.restart();
|
||||
}
|
||||
|
||||
@@ -121,12 +121,15 @@ namespace
|
||||
|
||||
void applyToTorrents(const QStringList &hashes, const std::function<void (BitTorrent::TorrentHandle *torrent)> &func)
|
||||
{
|
||||
if ((hashes.size() == 1) && (hashes[0] == QLatin1String("all"))) {
|
||||
if ((hashes.size() == 1) && (hashes[0] == QLatin1String("all")))
|
||||
{
|
||||
for (BitTorrent::TorrentHandle *const torrent : asConst(BitTorrent::Session::instance()->torrents()))
|
||||
func(torrent);
|
||||
}
|
||||
else {
|
||||
for (const QString &hash : hashes) {
|
||||
else
|
||||
{
|
||||
for (const QString &hash : hashes)
|
||||
{
|
||||
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
|
||||
if (torrent)
|
||||
func(torrent);
|
||||
@@ -137,10 +140,12 @@ namespace
|
||||
QJsonArray getStickyTrackers(const BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
int seedsDHT = 0, seedsPeX = 0, seedsLSD = 0, leechesDHT = 0, leechesPeX = 0, leechesLSD = 0;
|
||||
for (const BitTorrent::PeerInfo &peer : asConst(torrent->peers())) {
|
||||
for (const BitTorrent::PeerInfo &peer : asConst(torrent->peers()))
|
||||
{
|
||||
if (peer.isConnecting()) continue;
|
||||
|
||||
if (peer.isSeed()) {
|
||||
if (peer.isSeed())
|
||||
{
|
||||
if (peer.fromDHT())
|
||||
++seedsDHT;
|
||||
if (peer.fromPeX())
|
||||
@@ -148,7 +153,8 @@ namespace
|
||||
if (peer.fromLSD())
|
||||
++seedsLSD;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
if (peer.fromDHT())
|
||||
++leechesDHT;
|
||||
if (peer.fromPeX())
|
||||
@@ -164,7 +170,8 @@ namespace
|
||||
const QString privateMsg {QCoreApplication::translate("TrackerListWidget", "This torrent is private")};
|
||||
const bool isTorrentPrivate = torrent->isPrivate();
|
||||
|
||||
const QJsonObject dht {
|
||||
const QJsonObject dht
|
||||
{
|
||||
{KEY_TRACKER_URL, "** [DHT] **"},
|
||||
{KEY_TRACKER_TIER, ""},
|
||||
{KEY_TRACKER_MSG, (isTorrentPrivate ? privateMsg : "")},
|
||||
@@ -175,7 +182,8 @@ namespace
|
||||
{KEY_TRACKER_LEECHES_COUNT, leechesDHT}
|
||||
};
|
||||
|
||||
const QJsonObject pex {
|
||||
const QJsonObject pex
|
||||
{
|
||||
{KEY_TRACKER_URL, "** [PeX] **"},
|
||||
{KEY_TRACKER_TIER, ""},
|
||||
{KEY_TRACKER_MSG, (isTorrentPrivate ? privateMsg : "")},
|
||||
@@ -186,7 +194,8 @@ namespace
|
||||
{KEY_TRACKER_LEECHES_COUNT, leechesPeX}
|
||||
};
|
||||
|
||||
const QJsonObject lsd {
|
||||
const QJsonObject lsd
|
||||
{
|
||||
{KEY_TRACKER_URL, "** [LSD] **"},
|
||||
{KEY_TRACKER_TIER, ""},
|
||||
{KEY_TRACKER_MSG, (isTorrentPrivate ? privateMsg : "")},
|
||||
@@ -251,7 +260,8 @@ void TorrentsController::infoAction()
|
||||
|
||||
QVariantList torrentList;
|
||||
TorrentFilter torrentFilter(filter, (hashSet.isEmpty() ? TorrentFilter::AnyHash : hashSet), category);
|
||||
for (BitTorrent::TorrentHandle *const torrent : asConst(BitTorrent::Session::instance()->torrents())) {
|
||||
for (BitTorrent::TorrentHandle *const torrent : asConst(BitTorrent::Session::instance()->torrents()))
|
||||
{
|
||||
if (torrentFilter.match(torrent))
|
||||
torrentList.append(serialize(*torrent));
|
||||
}
|
||||
@@ -358,12 +368,14 @@ void TorrentsController::propertiesAction()
|
||||
dataDict[KEY_PROP_PIECES_HAVE] = torrent->piecesHave();
|
||||
dataDict[KEY_PROP_CREATED_BY] = torrent->creator();
|
||||
dataDict[KEY_PROP_ADDITION_DATE] = static_cast<double>(torrent->addedTime().toSecsSinceEpoch());
|
||||
if (torrent->hasMetadata()) {
|
||||
if (torrent->hasMetadata())
|
||||
{
|
||||
dataDict[KEY_PROP_LAST_SEEN] = torrent->lastSeenComplete().isValid() ? torrent->lastSeenComplete().toSecsSinceEpoch() : -1;
|
||||
dataDict[KEY_PROP_COMPLETION_DATE] = torrent->completedTime().isValid() ? torrent->completedTime().toSecsSinceEpoch() : -1;
|
||||
dataDict[KEY_PROP_CREATION_DATE] = static_cast<double>(torrent->creationDate().toSecsSinceEpoch());
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
dataDict[KEY_PROP_LAST_SEEN] = -1;
|
||||
dataDict[KEY_PROP_COMPLETION_DATE] = -1;
|
||||
dataDict[KEY_PROP_CREATION_DATE] = -1;
|
||||
@@ -397,10 +409,12 @@ void TorrentsController::trackersAction()
|
||||
QJsonArray trackerList = getStickyTrackers(torrent);
|
||||
|
||||
QHash<QString, BitTorrent::TrackerInfo> trackersData = torrent->trackerInfos();
|
||||
for (const BitTorrent::TrackerEntry &tracker : asConst(torrent->trackers())) {
|
||||
for (const BitTorrent::TrackerEntry &tracker : asConst(torrent->trackers()))
|
||||
{
|
||||
const BitTorrent::TrackerInfo data = trackersData.value(tracker.url());
|
||||
|
||||
trackerList << QJsonObject {
|
||||
trackerList << QJsonObject
|
||||
{
|
||||
{KEY_TRACKER_URL, tracker.url()},
|
||||
{KEY_TRACKER_TIER, tracker.tier()},
|
||||
{KEY_TRACKER_STATUS, static_cast<int>(tracker.status())},
|
||||
@@ -429,8 +443,10 @@ void TorrentsController::webseedsAction()
|
||||
throw APIError(APIErrorType::NotFound);
|
||||
|
||||
QJsonArray webSeedList;
|
||||
for (const QUrl &webseed : asConst(torrent->urlSeeds())) {
|
||||
webSeedList.append(QJsonObject {
|
||||
for (const QUrl &webseed : asConst(torrent->urlSeeds()))
|
||||
{
|
||||
webSeedList.append(QJsonObject
|
||||
{
|
||||
{KEY_WEBSEED_URL, webseed.toString()}
|
||||
});
|
||||
}
|
||||
@@ -458,13 +474,16 @@ void TorrentsController::filesAction()
|
||||
throw APIError(APIErrorType::NotFound);
|
||||
|
||||
QJsonArray fileList;
|
||||
if (torrent->hasMetadata()) {
|
||||
if (torrent->hasMetadata())
|
||||
{
|
||||
const QVector<BitTorrent::DownloadPriority> priorities = torrent->filePriorities();
|
||||
const QVector<qreal> fp = torrent->filesProgress();
|
||||
const QVector<qreal> fileAvailability = torrent->availableFileFractions();
|
||||
const BitTorrent::TorrentInfo info = torrent->info();
|
||||
for (int i = 0; i < torrent->filesCount(); ++i) {
|
||||
QJsonObject fileDict = {
|
||||
for (int i = 0; i < torrent->filesCount(); ++i)
|
||||
{
|
||||
QJsonObject fileDict =
|
||||
{
|
||||
{KEY_FILE_PROGRESS, fp[i]},
|
||||
{KEY_FILE_PRIORITY, static_cast<int>(priorities[i])},
|
||||
{KEY_FILE_SIZE, torrent->fileSize(i)},
|
||||
@@ -528,7 +547,8 @@ void TorrentsController::pieceStatesAction()
|
||||
pieceStates.append(static_cast<int>(states[i]) * 2);
|
||||
|
||||
const QBitArray dlstates = torrent->downloadingPieces();
|
||||
for (int i = 0; i < states.size(); ++i) {
|
||||
for (int i = 0; i < states.size(); ++i)
|
||||
{
|
||||
if (dlstates[i])
|
||||
pieceStates[i] = 1;
|
||||
}
|
||||
@@ -554,12 +574,15 @@ void TorrentsController::addAction()
|
||||
const TriStateBool autoTMM = parseTriStateBool(params()["autoTMM"]);
|
||||
|
||||
QList<QNetworkCookie> cookies;
|
||||
if (!cookie.isEmpty()) {
|
||||
if (!cookie.isEmpty())
|
||||
{
|
||||
const QStringList cookiesStr = cookie.split("; ");
|
||||
for (QString cookieStr : cookiesStr) {
|
||||
for (QString cookieStr : cookiesStr)
|
||||
{
|
||||
cookieStr = cookieStr.trimmed();
|
||||
int index = cookieStr.indexOf('=');
|
||||
if (index > 1) {
|
||||
if (index > 1)
|
||||
{
|
||||
QByteArray name = cookieStr.left(index).toLatin1();
|
||||
QByteArray value = cookieStr.right(cookieStr.length() - index - 1).toLatin1();
|
||||
cookies += QNetworkCookie(name, value);
|
||||
@@ -582,17 +605,21 @@ void TorrentsController::addAction()
|
||||
params.useAutoTMM = autoTMM;
|
||||
|
||||
bool partialSuccess = false;
|
||||
for (QString url : asConst(urls.split('\n'))) {
|
||||
for (QString url : asConst(urls.split('\n')))
|
||||
{
|
||||
url = url.trimmed();
|
||||
if (!url.isEmpty()) {
|
||||
if (!url.isEmpty())
|
||||
{
|
||||
Net::DownloadManager::instance()->setCookiesFromUrl(cookies, QUrl::fromEncoded(url.toUtf8()));
|
||||
partialSuccess |= BitTorrent::Session::instance()->addTorrent(url, params);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = data().constBegin(); it != data().constEnd(); ++it) {
|
||||
for (auto it = data().constBegin(); it != data().constEnd(); ++it)
|
||||
{
|
||||
const BitTorrent::TorrentInfo torrentInfo = BitTorrent::TorrentInfo::load(it.value());
|
||||
if (!torrentInfo.isValid()) {
|
||||
if (!torrentInfo.isValid())
|
||||
{
|
||||
throw APIError(APIErrorType::BadData
|
||||
, tr("Error: '%1' is not a valid torrent file.").arg(it.key()));
|
||||
}
|
||||
@@ -616,7 +643,8 @@ void TorrentsController::addTrackersAction()
|
||||
throw APIError(APIErrorType::NotFound);
|
||||
|
||||
QVector<BitTorrent::TrackerEntry> trackers;
|
||||
for (const QString &urlStr : asConst(params()["urls"].split('\n'))) {
|
||||
for (const QString &urlStr : asConst(params()["urls"].split('\n')))
|
||||
{
|
||||
const QUrl url {urlStr.trimmed()};
|
||||
if (url.isValid())
|
||||
trackers << url.toString();
|
||||
@@ -645,11 +673,13 @@ void TorrentsController::editTrackerAction()
|
||||
|
||||
QVector<BitTorrent::TrackerEntry> trackers = torrent->trackers();
|
||||
bool match = false;
|
||||
for (BitTorrent::TrackerEntry &tracker : trackers) {
|
||||
for (BitTorrent::TrackerEntry &tracker : trackers)
|
||||
{
|
||||
const QUrl trackerUrl(tracker.url());
|
||||
if (trackerUrl == newTrackerUrl)
|
||||
throw APIError(APIErrorType::Conflict, "New tracker URL already exists");
|
||||
if (trackerUrl == origTrackerUrl) {
|
||||
if (trackerUrl == origTrackerUrl)
|
||||
{
|
||||
match = true;
|
||||
BitTorrent::TrackerEntry newTracker(newTrackerUrl.toString());
|
||||
newTracker.setTier(tracker.tier());
|
||||
@@ -679,7 +709,8 @@ void TorrentsController::removeTrackersAction()
|
||||
const QVector<BitTorrent::TrackerEntry> trackers = torrent->trackers();
|
||||
QVector<BitTorrent::TrackerEntry> remainingTrackers;
|
||||
remainingTrackers.reserve(trackers.size());
|
||||
for (const BitTorrent::TrackerEntry &entry : trackers) {
|
||||
for (const BitTorrent::TrackerEntry &entry : trackers)
|
||||
{
|
||||
if (!urls.contains(entry.url()))
|
||||
remainingTrackers.push_back(entry);
|
||||
}
|
||||
@@ -702,7 +733,8 @@ void TorrentsController::addPeersAction()
|
||||
|
||||
QVector<BitTorrent::PeerAddress> peerList;
|
||||
peerList.reserve(peers.size());
|
||||
for (const QString &peer : peers) {
|
||||
for (const QString &peer : peers)
|
||||
{
|
||||
const BitTorrent::PeerAddress addr = BitTorrent::PeerAddress::parse(peer.trimmed());
|
||||
if (!addr.ip.isNull())
|
||||
peerList.append(addr);
|
||||
@@ -720,7 +752,8 @@ void TorrentsController::addPeersAction()
|
||||
return torrent->connectPeer(peer);
|
||||
});
|
||||
|
||||
results[torrent->hash()] = QJsonObject {
|
||||
results[torrent->hash()] = QJsonObject
|
||||
{
|
||||
{"added", peersAdded},
|
||||
{"failed", (peers.size() - peersAdded)}
|
||||
};
|
||||
@@ -767,14 +800,16 @@ void TorrentsController::filePrioAction()
|
||||
const int filesCount = torrent->filesCount();
|
||||
QVector<BitTorrent::DownloadPriority> priorities = torrent->filePriorities();
|
||||
bool priorityChanged = false;
|
||||
for (const QString &fileID : params()["id"].split('|')) {
|
||||
for (const QString &fileID : params()["id"].split('|'))
|
||||
{
|
||||
const int id = fileID.toInt(&ok);
|
||||
if (!ok)
|
||||
throw APIError(APIErrorType::BadParams, tr("File IDs must be integers"));
|
||||
if ((id < 0) || (id >= filesCount))
|
||||
throw APIError(APIErrorType::Conflict, tr("File ID is not valid"));
|
||||
|
||||
if (priorities[id] != priority) {
|
||||
if (priorities[id] != priority)
|
||||
{
|
||||
priorities[id] = priority;
|
||||
priorityChanged = true;
|
||||
}
|
||||
@@ -790,7 +825,8 @@ void TorrentsController::uploadLimitAction()
|
||||
|
||||
const QStringList hashes {params()["hashes"].split('|')};
|
||||
QJsonObject map;
|
||||
for (const QString &hash : hashes) {
|
||||
for (const QString &hash : hashes)
|
||||
{
|
||||
int limit = -1;
|
||||
const BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
|
||||
if (torrent)
|
||||
@@ -807,7 +843,8 @@ void TorrentsController::downloadLimitAction()
|
||||
|
||||
const QStringList hashes {params()["hashes"].split('|')};
|
||||
QJsonObject map;
|
||||
for (const QString &hash : hashes) {
|
||||
for (const QString &hash : hashes)
|
||||
{
|
||||
int limit = -1;
|
||||
const BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
|
||||
if (torrent)
|
||||
@@ -1082,9 +1119,11 @@ void TorrentsController::categoriesAction()
|
||||
{
|
||||
QJsonObject categories;
|
||||
const QStringMap categoriesMap = BitTorrent::Session::instance()->categories();
|
||||
for (auto it = categoriesMap.cbegin(); it != categoriesMap.cend(); ++it) {
|
||||
for (auto it = categoriesMap.cbegin(); it != categoriesMap.cend(); ++it)
|
||||
{
|
||||
const auto &key = it.key();
|
||||
categories[key] = QJsonObject {
|
||||
categories[key] = QJsonObject
|
||||
{
|
||||
{"name", key},
|
||||
{"savePath", it.value()}
|
||||
};
|
||||
@@ -1100,7 +1139,8 @@ void TorrentsController::addTagsAction()
|
||||
const QStringList hashes {params()["hashes"].split('|')};
|
||||
const QStringList tags {params()["tags"].split(',', QString::SkipEmptyParts)};
|
||||
|
||||
for (const QString &tag : tags) {
|
||||
for (const QString &tag : tags)
|
||||
{
|
||||
const QString tagTrimmed {tag.trimmed()};
|
||||
applyToTorrents(hashes, [&tagTrimmed](BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
@@ -1116,7 +1156,8 @@ void TorrentsController::removeTagsAction()
|
||||
const QStringList hashes {params()["hashes"].split('|')};
|
||||
const QStringList tags {params()["tags"].split(',', QString::SkipEmptyParts)};
|
||||
|
||||
for (const QString &tag : tags) {
|
||||
for (const QString &tag : tags)
|
||||
{
|
||||
const QString tagTrimmed {tag.trimmed()};
|
||||
applyToTorrents(hashes, [&tagTrimmed](BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
@@ -1124,7 +1165,8 @@ void TorrentsController::removeTagsAction()
|
||||
});
|
||||
}
|
||||
|
||||
if (tags.isEmpty()) {
|
||||
if (tags.isEmpty())
|
||||
{
|
||||
applyToTorrents(hashes, [](BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
torrent->removeAllTags();
|
||||
@@ -1193,7 +1235,8 @@ void TorrentsController::renameFileAction()
|
||||
return;
|
||||
|
||||
// check if new name is already used
|
||||
for (int i = 0; i < torrent->filesCount(); ++i) {
|
||||
for (int i = 0; i < torrent->filesCount(); ++i)
|
||||
{
|
||||
if (i == fileIndex) continue;
|
||||
if (Utils::Fs::sameFileNames(torrent->filePath(i), newFilePath))
|
||||
throw APIError(APIErrorType::Conflict, tr("Name is already in use"));
|
||||
|
||||
@@ -122,7 +122,8 @@ void TransferController::banPeersAction()
|
||||
requireParams({"peers"});
|
||||
|
||||
const QStringList peers = params()["peers"].split('|');
|
||||
for (const QString &peer : peers) {
|
||||
for (const QString &peer : peers)
|
||||
{
|
||||
const BitTorrent::PeerAddress addr = BitTorrent::PeerAddress::parse(peer.trimmed());
|
||||
if (!addr.ip.isNull())
|
||||
BitTorrent::Session::instance()->banIP(addr.ip.toString());
|
||||
|
||||
@@ -77,7 +77,8 @@ namespace
|
||||
QStringMap ret;
|
||||
const QVector<QStringRef> cookies = cookieStr.splitRef(';', QString::SkipEmptyParts);
|
||||
|
||||
for (const auto &cookie : cookies) {
|
||||
for (const auto &cookie : cookies)
|
||||
{
|
||||
const int idx = cookie.indexOf('=');
|
||||
if (idx < 0)
|
||||
continue;
|
||||
@@ -104,7 +105,8 @@ namespace
|
||||
return QLatin1String("private, max-age=604800"); // 1 week
|
||||
|
||||
if ((contentType == Http::CONTENT_TYPE_CSS)
|
||||
|| (contentType == Http::CONTENT_TYPE_JS)) {
|
||||
|| (contentType == Http::CONTENT_TYPE_JS))
|
||||
{
|
||||
// short interval in case of program update
|
||||
return QLatin1String("private, max-age=43200"); // 12 hrs
|
||||
}
|
||||
@@ -144,21 +146,25 @@ void WebApplication::sendWebUIFile()
|
||||
if (pathItems.contains(".") || pathItems.contains(".."))
|
||||
throw InternalServerErrorHTTPError();
|
||||
|
||||
if (!m_isAltUIUsed) {
|
||||
if (request().path.startsWith(PATH_PREFIX_ICONS)) {
|
||||
if (!m_isAltUIUsed)
|
||||
{
|
||||
if (request().path.startsWith(PATH_PREFIX_ICONS))
|
||||
{
|
||||
const QString imageFilename {request().path.mid(PATH_PREFIX_ICONS.size())};
|
||||
sendFile(QLatin1String(":/icons/") + imageFilename);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const QString path {
|
||||
const QString path
|
||||
{
|
||||
(request().path != QLatin1String("/")
|
||||
? request().path
|
||||
: QLatin1String("/index.html"))
|
||||
};
|
||||
|
||||
QString localPath {
|
||||
QString localPath
|
||||
{
|
||||
m_rootFolder
|
||||
+ (session() ? PRIVATE_FOLDER : PUBLIC_FOLDER)
|
||||
+ path
|
||||
@@ -166,22 +172,26 @@ void WebApplication::sendWebUIFile()
|
||||
|
||||
QFileInfo fileInfo {localPath};
|
||||
|
||||
if (!fileInfo.exists() && session()) {
|
||||
if (!fileInfo.exists() && session())
|
||||
{
|
||||
// try to send public file if there is no private one
|
||||
localPath = m_rootFolder + PUBLIC_FOLDER + path;
|
||||
fileInfo.setFile(localPath);
|
||||
}
|
||||
|
||||
if (m_isAltUIUsed) {
|
||||
if (m_isAltUIUsed)
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
if (!Utils::Fs::isRegularFile(localPath)) {
|
||||
if (!Utils::Fs::isRegularFile(localPath))
|
||||
{
|
||||
status(500, "Internal Server Error");
|
||||
print(tr("Unacceptable file type, only regular file is allowed."), Http::CONTENT_TYPE_TXT);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
while (fileInfo.filePath() != m_rootFolder) {
|
||||
while (fileInfo.filePath() != m_rootFolder)
|
||||
{
|
||||
if (fileInfo.isSymLink())
|
||||
throw InternalServerErrorHTTPError(tr("Symlinks inside alternative UI folder are forbidden."));
|
||||
|
||||
@@ -198,10 +208,12 @@ void WebApplication::translateDocument(QString &data) const
|
||||
|
||||
int i = 0;
|
||||
bool found = true;
|
||||
while (i < data.size() && found) {
|
||||
while (i < data.size() && found)
|
||||
{
|
||||
QRegularExpressionMatch regexMatch;
|
||||
i = data.indexOf(regex, i, ®exMatch);
|
||||
if (i >= 0) {
|
||||
if (i >= 0)
|
||||
{
|
||||
const QString sourceText = regexMatch.captured(1);
|
||||
const QString context = regexMatch.captured(3);
|
||||
|
||||
@@ -219,7 +231,8 @@ void WebApplication::translateDocument(QString &data) const
|
||||
data.replace(i, regexMatch.capturedLength(), translation);
|
||||
i += translation.length();
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
found = false; // no more translatable strings
|
||||
}
|
||||
|
||||
@@ -246,7 +259,8 @@ const Http::Environment &WebApplication::env() const
|
||||
void WebApplication::doProcessRequest()
|
||||
{
|
||||
const QRegularExpressionMatch match = m_apiPathPattern.match(request().path);
|
||||
if (!match.hasMatch()) {
|
||||
if (!match.hasMatch())
|
||||
{
|
||||
sendWebUIFile();
|
||||
return;
|
||||
}
|
||||
@@ -265,9 +279,11 @@ void WebApplication::doProcessRequest()
|
||||
for (const Http::UploadedFile &torrent : request().files)
|
||||
data[torrent.filename] = torrent.data;
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
const QVariant result = controller->run(action, m_params, data);
|
||||
switch (result.userType()) {
|
||||
switch (result.userType())
|
||||
{
|
||||
case QMetaType::QJsonDocument:
|
||||
print(result.toJsonDocument().toJson(QJsonDocument::Compact), Http::CONTENT_TYPE_JSON);
|
||||
break;
|
||||
@@ -277,9 +293,11 @@ void WebApplication::doProcessRequest()
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (const APIError &error) {
|
||||
catch (const APIError &error)
|
||||
{
|
||||
// re-throw as HTTPError
|
||||
switch (error.type()) {
|
||||
switch (error.type())
|
||||
{
|
||||
case APIErrorType::AccessDenied:
|
||||
throw ForbiddenHTTPError(error.message());
|
||||
case APIErrorType::BadData:
|
||||
@@ -303,7 +321,8 @@ void WebApplication::configure()
|
||||
const bool isAltUIUsed = pref->isAltWebUiEnabled();
|
||||
const QString rootFolder = Utils::Fs::expandPathAbs(
|
||||
!isAltUIUsed ? WWW_FOLDER : pref->getWebUiRootFolder());
|
||||
if ((isAltUIUsed != m_isAltUIUsed) || (rootFolder != m_rootFolder)) {
|
||||
if ((isAltUIUsed != m_isAltUIUsed) || (rootFolder != m_rootFolder))
|
||||
{
|
||||
m_isAltUIUsed = isAltUIUsed;
|
||||
m_rootFolder = rootFolder;
|
||||
m_translatedFiles.clear();
|
||||
@@ -314,16 +333,19 @@ void WebApplication::configure()
|
||||
}
|
||||
|
||||
const QString newLocale = pref->getLocale();
|
||||
if (m_currentLocale != newLocale) {
|
||||
if (m_currentLocale != newLocale)
|
||||
{
|
||||
m_currentLocale = newLocale;
|
||||
m_translatedFiles.clear();
|
||||
|
||||
m_translationFileLoaded = m_translator.load(m_rootFolder + QLatin1String("/translations/webui_") + newLocale);
|
||||
if (m_translationFileLoaded) {
|
||||
if (m_translationFileLoaded)
|
||||
{
|
||||
LogMsg(tr("Web UI translation for selected locale (%1) has been successfully loaded.")
|
||||
.arg(newLocale));
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
LogMsg(tr("Couldn't load Web UI translation for selected locale (%1).").arg(newLocale), Log::WARNING);
|
||||
}
|
||||
}
|
||||
@@ -361,13 +383,16 @@ void WebApplication::configure()
|
||||
if (!contentSecurityPolicy.isEmpty())
|
||||
m_prebuiltHeaders.push_back({QLatin1String(Http::HEADER_CONTENT_SECURITY_POLICY), contentSecurityPolicy});
|
||||
|
||||
if (pref->isWebUICustomHTTPHeadersEnabled()) {
|
||||
if (pref->isWebUICustomHTTPHeadersEnabled())
|
||||
{
|
||||
const QString customHeaders = pref->getWebUICustomHTTPHeaders().trimmed();
|
||||
const QVector<QStringRef> customHeaderLines = customHeaders.splitRef('\n', QString::SkipEmptyParts);
|
||||
|
||||
for (const QStringRef &line : customHeaderLines) {
|
||||
for (const QStringRef &line : customHeaderLines)
|
||||
{
|
||||
const int idx = line.indexOf(':');
|
||||
if (idx < 0) {
|
||||
if (idx < 0)
|
||||
{
|
||||
// require separator `:` to be present even if `value` field can be empty
|
||||
LogMsg(tr("Missing ':' separator in WebUI custom HTTP header: \"%1\"").arg(line.toString()), Log::WARNING);
|
||||
continue;
|
||||
@@ -399,19 +424,22 @@ void WebApplication::sendFile(const QString &path)
|
||||
|
||||
// find translated file in cache
|
||||
const auto it = m_translatedFiles.constFind(path);
|
||||
if ((it != m_translatedFiles.constEnd()) && (lastModified <= it->lastModified)) {
|
||||
if ((it != m_translatedFiles.constEnd()) && (lastModified <= it->lastModified))
|
||||
{
|
||||
print(it->data, it->mimeType);
|
||||
setHeader({Http::HEADER_CACHE_CONTROL, getCachingInterval(it->mimeType)});
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file {path};
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
qDebug("File %s was not found!", qUtf8Printable(path));
|
||||
throw NotFoundHTTPError();
|
||||
}
|
||||
|
||||
if (file.size() > MAX_ALLOWED_FILESIZE) {
|
||||
if (file.size() > MAX_ALLOWED_FILESIZE)
|
||||
{
|
||||
qWarning("%s: exceeded the maximum allowed file size!", qUtf8Printable(path));
|
||||
throw InternalServerErrorHTTPError(tr("Exceeded the maximum allowed file size (%1)!")
|
||||
.arg(Utils::Misc::friendlyUnit(MAX_ALLOWED_FILESIZE)));
|
||||
@@ -424,7 +452,8 @@ void WebApplication::sendFile(const QString &path)
|
||||
const bool isTranslatable {mimeType.inherits(QLatin1String("text/plain"))};
|
||||
|
||||
// Translate the file
|
||||
if (isTranslatable) {
|
||||
if (isTranslatable)
|
||||
{
|
||||
QString dataStr {data};
|
||||
translateDocument(dataStr);
|
||||
data = dataStr.toUtf8();
|
||||
@@ -443,28 +472,33 @@ Http::Response WebApplication::processRequest(const Http::Request &request, cons
|
||||
m_env = env;
|
||||
m_params.clear();
|
||||
|
||||
if (m_request.method == Http::METHOD_GET) {
|
||||
if (m_request.method == Http::METHOD_GET)
|
||||
{
|
||||
for (auto iter = m_request.query.cbegin(); iter != m_request.query.cend(); ++iter)
|
||||
m_params[iter.key()] = QString::fromUtf8(iter.value());
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
m_params = m_request.posts;
|
||||
}
|
||||
|
||||
// clear response
|
||||
clear();
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
// block suspicious requests
|
||||
if ((m_isCSRFProtectionEnabled && isCrossSiteRequest(m_request))
|
||||
|| (m_isHostHeaderValidationEnabled && !validateHostHeader(m_domainList))) {
|
||||
|| (m_isHostHeaderValidationEnabled && !validateHostHeader(m_domainList)))
|
||||
{
|
||||
throw UnauthorizedHTTPError();
|
||||
}
|
||||
|
||||
sessionInitialize();
|
||||
doProcessRequest();
|
||||
}
|
||||
catch (const HTTPError &error) {
|
||||
catch (const HTTPError &error)
|
||||
{
|
||||
status(error.statusCode(), error.statusText());
|
||||
print((!error.message().isEmpty() ? error.message() : error.statusText()), Http::CONTENT_TYPE_TXT);
|
||||
}
|
||||
@@ -488,19 +522,24 @@ void WebApplication::sessionInitialize()
|
||||
|
||||
// TODO: Additional session check
|
||||
|
||||
if (!sessionId.isEmpty()) {
|
||||
if (!sessionId.isEmpty())
|
||||
{
|
||||
m_currentSession = m_sessions.value(sessionId);
|
||||
if (m_currentSession) {
|
||||
if (m_currentSession->hasExpired(m_sessionTimeout)) {
|
||||
if (m_currentSession)
|
||||
{
|
||||
if (m_currentSession->hasExpired(m_sessionTimeout))
|
||||
{
|
||||
// session is outdated - removing it
|
||||
delete m_sessions.take(sessionId);
|
||||
m_currentSession = nullptr;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
m_currentSession->updateTimestamp();
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "session does not exist!";
|
||||
}
|
||||
}
|
||||
@@ -513,8 +552,10 @@ QString WebApplication::generateSid() const
|
||||
{
|
||||
QString sid;
|
||||
|
||||
do {
|
||||
const quint32 tmp[] = {Utils::Random::rand(), Utils::Random::rand(), Utils::Random::rand()
|
||||
do
|
||||
{
|
||||
const quint32 tmp[] =
|
||||
{Utils::Random::rand(), Utils::Random::rand(), Utils::Random::rand()
|
||||
, Utils::Random::rand(), Utils::Random::rand(), Utils::Random::rand()};
|
||||
sid = QByteArray::fromRawData(reinterpret_cast<const char *>(tmp), sizeof(tmp)).toBase64();
|
||||
}
|
||||
@@ -544,7 +585,8 @@ void WebApplication::sessionStart()
|
||||
// remove outdated sessions
|
||||
Algorithm::removeIf(m_sessions, [this](const QString &, const WebSession *session)
|
||||
{
|
||||
if (session->hasExpired(m_sessionTimeout)) {
|
||||
if (session->hasExpired(m_sessionTimeout))
|
||||
{
|
||||
delete session;
|
||||
return true;
|
||||
}
|
||||
@@ -595,14 +637,16 @@ bool WebApplication::isCrossSiteRequest(const Http::Request &request) const
|
||||
const QString originValue = request.headers.value(Http::HEADER_ORIGIN);
|
||||
const QString refererValue = request.headers.value(Http::HEADER_REFERER);
|
||||
|
||||
if (originValue.isEmpty() && refererValue.isEmpty()) {
|
||||
if (originValue.isEmpty() && refererValue.isEmpty())
|
||||
{
|
||||
// owasp.org recommends to block this request, but doing so will inevitably lead Web API users to spoof headers
|
||||
// so lets be permissive here
|
||||
return false;
|
||||
}
|
||||
|
||||
// sent with CORS requests, as well as with POST requests
|
||||
if (!originValue.isEmpty()) {
|
||||
if (!originValue.isEmpty())
|
||||
{
|
||||
const bool isInvalid = !isSameOrigin(urlFromHostHeader(targetOrigin), originValue);
|
||||
if (isInvalid)
|
||||
LogMsg(tr("WebUI: Origin header & Target origin mismatch! Source IP: '%1'. Origin header: '%2'. Target origin: '%3'")
|
||||
@@ -611,7 +655,8 @@ bool WebApplication::isCrossSiteRequest(const Http::Request &request) const
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
if (!refererValue.isEmpty()) {
|
||||
if (!refererValue.isEmpty())
|
||||
{
|
||||
const bool isInvalid = !isSameOrigin(urlFromHostHeader(targetOrigin), refererValue);
|
||||
if (isInvalid)
|
||||
LogMsg(tr("WebUI: Referer header & Target origin mismatch! Source IP: '%1'. Referer header: '%2'. Target origin: '%3'")
|
||||
@@ -630,7 +675,8 @@ bool WebApplication::validateHostHeader(const QStringList &domains) const
|
||||
|
||||
// (if present) try matching host header's port with local port
|
||||
const int requestPort = hostHeader.port();
|
||||
if ((requestPort != -1) && (m_env.localPort != requestPort)) {
|
||||
if ((requestPort != -1) && (m_env.localPort != requestPort))
|
||||
{
|
||||
LogMsg(tr("WebUI: Invalid Host header, port mismatch. Request source IP: '%1'. Server port: '%2'. Received Host header: '%3'")
|
||||
.arg(m_env.clientAddress.toString()).arg(m_env.localPort)
|
||||
.arg(m_request.headers[Http::HEADER_HOST])
|
||||
@@ -645,7 +691,8 @@ bool WebApplication::validateHostHeader(const QStringList &domains) const
|
||||
return true;
|
||||
|
||||
// try matching host header with domain list
|
||||
for (const auto &domain : domains) {
|
||||
for (const auto &domain : domains)
|
||||
{
|
||||
QRegExp domainRegex(domain, Qt::CaseInsensitive, QRegExp::Wildcard);
|
||||
if (requestHost.contains(domainRegex))
|
||||
return true;
|
||||
|
||||
@@ -56,31 +56,38 @@ void WebUI::configure()
|
||||
const quint16 oldPort = m_port;
|
||||
m_port = pref->getWebUiPort();
|
||||
|
||||
if (pref->isWebUiEnabled()) {
|
||||
if (pref->isWebUiEnabled())
|
||||
{
|
||||
// UPnP/NAT-PMP
|
||||
if (pref->useUPnPForWebUIPort()) {
|
||||
if (m_port != oldPort) {
|
||||
if (pref->useUPnPForWebUIPort())
|
||||
{
|
||||
if (m_port != oldPort)
|
||||
{
|
||||
Net::PortForwarder::instance()->deletePort(oldPort);
|
||||
Net::PortForwarder::instance()->addPort(m_port);
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
Net::PortForwarder::instance()->deletePort(oldPort);
|
||||
}
|
||||
|
||||
// http server
|
||||
const QString serverAddressString = pref->getWebUiAddress();
|
||||
if (!m_httpServer) {
|
||||
if (!m_httpServer)
|
||||
{
|
||||
m_webapp = new WebApplication(this);
|
||||
m_httpServer = new Http::Server(m_webapp, this);
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
if ((m_httpServer->serverAddress().toString() != serverAddressString)
|
||||
|| (m_httpServer->serverPort() != m_port))
|
||||
m_httpServer->close();
|
||||
}
|
||||
|
||||
if (pref->isWebUiHttpsEnabled()) {
|
||||
if (pref->isWebUiHttpsEnabled())
|
||||
{
|
||||
const auto readData = [](const QString &path) -> QByteArray
|
||||
{
|
||||
QFile file(path);
|
||||
@@ -97,18 +104,22 @@ void WebUI::configure()
|
||||
else
|
||||
logger->addMessage(tr("Web UI: HTTPS setup failed, fallback to HTTP"), Log::CRITICAL);
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
m_httpServer->disableHttps();
|
||||
}
|
||||
|
||||
if (!m_httpServer->isListening()) {
|
||||
if (!m_httpServer->isListening())
|
||||
{
|
||||
const auto address = (serverAddressString == "*" || serverAddressString.isEmpty())
|
||||
? QHostAddress::Any : QHostAddress(serverAddressString);
|
||||
bool success = m_httpServer->listen(address, m_port);
|
||||
if (success) {
|
||||
if (success)
|
||||
{
|
||||
logger->addMessage(tr("Web UI: Now listening on IP: %1, port: %2").arg(serverAddressString).arg(m_port));
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
const QString errorMsg = tr("Web UI: Unable to bind to IP: %1, port: %2. Reason: %3")
|
||||
.arg(serverAddressString).arg(m_port).arg(m_httpServer->errorString());
|
||||
logger->addMessage(errorMsg, Log::CRITICAL);
|
||||
@@ -120,17 +131,20 @@ void WebUI::configure()
|
||||
}
|
||||
|
||||
// DynDNS
|
||||
if (pref->isDynDNSEnabled()) {
|
||||
if (pref->isDynDNSEnabled())
|
||||
{
|
||||
if (!m_dnsUpdater)
|
||||
m_dnsUpdater = new Net::DNSUpdater(this);
|
||||
else
|
||||
m_dnsUpdater->updateCredentials();
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
delete m_dnsUpdater;
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
Net::PortForwarder::instance()->deletePort(oldPort);
|
||||
|
||||
delete m_httpServer;
|
||||
|
||||
Reference in New Issue
Block a user