diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0aab08ca..e6e8b94a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
project (airdcpp-webclient)
-cmake_minimum_required (VERSION 2.6.3)
+cmake_minimum_required (VERSION 2.8.6)
if (APPLE)
set (PROJECT_NAME_GLOBAL AirDC++ Web Client)
diff --git a/airdcpp-core/CMakeLists.txt b/airdcpp-core/CMakeLists.txt
index 73abc08b..3c30f0ed 100644
--- a/airdcpp-core/CMakeLists.txt
+++ b/airdcpp-core/CMakeLists.txt
@@ -39,6 +39,8 @@ add_library (airdcpp ${LINK} ${airdcpp_srcs})
# set_property(SOURCE ${PROJECT_SOURCE_DIR}/DCPlusPlus.cpp ${PROJECT_SOURCE_DIR}/UPnPManager.cpp PROPERTY COMPILE_DEFINITIONS USE_MINIUPNP )
#endif()
+
+set_property(SOURCE ${PROJECT_SOURCE_DIR}/airdcpp/StringDefs.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -fno-var-tracking ")
set_property(SOURCE ${PROJECT_SOURCE_DIR}/airdcpp/Updater.h PROPERTY COMPILE_DEFINITIONS NO_CLIENT_UPDATER)
add_definitions (-DNO_CLIENT_UPDATER)
diff --git a/airdcpp-core/airdcpp.vcxproj b/airdcpp-core/airdcpp.vcxproj
index 6b6d4520..f92010da 100644
--- a/airdcpp-core/airdcpp.vcxproj
+++ b/airdcpp-core/airdcpp.vcxproj
@@ -234,6 +234,7 @@
+
@@ -346,6 +347,7 @@
+
diff --git a/airdcpp-core/airdcpp.vcxproj.filters b/airdcpp-core/airdcpp.vcxproj.filters
index 6f1043ee..cf6cbb62 100644
--- a/airdcpp-core/airdcpp.vcxproj.filters
+++ b/airdcpp-core/airdcpp.vcxproj.filters
@@ -326,6 +326,9 @@
Source Files
+
+ Source Files
+
@@ -847,6 +850,9 @@
Header Files
+
+ Header Files
+
diff --git a/airdcpp-core/airdcpp/ActivityManager.cpp b/airdcpp-core/airdcpp/ActivityManager.cpp
new file mode 100644
index 00000000..25a4def0
--- /dev/null
+++ b/airdcpp-core/airdcpp/ActivityManager.cpp
@@ -0,0 +1,80 @@
+/*
+* Copyright (C) 2011-2016 AirDC++ Project
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "stdinc.h"
+
+#include "ActivityManager.h"
+#include "ClientManager.h"
+#include "SettingsManager.h"
+
+
+namespace dcpp {
+
+ActivityManager::ActivityManager() {
+ TimerManager::getInstance()->addListener(this);
+}
+
+ActivityManager::~ActivityManager() {
+ TimerManager::getInstance()->removeListener(this);
+}
+
+void ActivityManager::updateActivity(time_t aLastActivity) noexcept {
+ if (aLastActivity < lastActivity) {
+ return;
+ }
+
+ lastActivity = aLastActivity;
+ if (awayMode != AWAY_MANUAL) {
+ setAway(AWAY_OFF);
+ }
+}
+
+void ActivityManager::on(TimerManagerListener::Second, uint64_t aTick) noexcept {
+ if (!SETTING(AWAY_IDLE_TIME) || awayMode != AWAY_OFF) {
+ return;
+ }
+
+ if ((lastActivity + SETTING(AWAY_IDLE_TIME) * 60 * 1000ULL) < aTick) {
+ setAway(AWAY_IDLE);
+ }
+}
+
+void ActivityManager::setAway(AwayMode aNewMode) {
+ if (aNewMode == awayMode) {
+ return;
+ }
+
+ if (aNewMode == AWAY_MANUAL || (awayMode == AWAY_MANUAL && aNewMode == AWAY_OFF)) {
+ //only save the state if away mode is set by user
+ SettingsManager::getInstance()->set(SettingsManager::AWAY, aNewMode != AWAY_OFF);
+ }
+
+ awayMode = aNewMode;
+ if (awayMode > AWAY_OFF)
+ lastActivity = GET_TICK();
+
+ ClientManager::getInstance()->infoUpdated();
+ fire(ActivityManagerListener::AwayModeChanged(), awayMode);
+}
+
+string ActivityManager::getAwayMessage(const string& aAwayMsg, ParamMap& params) const noexcept {
+ params["idleTI"] = Util::formatSeconds(GET_TICK() - lastActivity);
+ return Util::formatParams(aAwayMsg, params);
+}
+
+} // namespace dcpp
\ No newline at end of file
diff --git a/airdcpp-core/airdcpp/ActivityManager.h b/airdcpp-core/airdcpp/ActivityManager.h
new file mode 100644
index 00000000..a9347c28
--- /dev/null
+++ b/airdcpp-core/airdcpp/ActivityManager.h
@@ -0,0 +1,68 @@
+/*
+* Copyright (C) 2011-2016 AirDC++ Project
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef DCPLUSPLUS_DCPP_ACTIVITY_MANAGER_H
+#define DCPLUSPLUS_DCPP_ACTIVITY_MANAGER_H
+
+#include "typedefs.h"
+
+#include "Speaker.h"
+#include "TimerManager.h"
+
+
+namespace dcpp {
+ //Away modes
+ enum AwayMode : uint8_t {
+ AWAY_OFF,
+ AWAY_IDLE,
+ AWAY_MANUAL //highest value
+ };
+
+ class ActivityManagerListener {
+ public:
+ virtual ~ActivityManagerListener() { }
+ template struct X { enum { TYPE = I }; };
+
+ typedef X<0> AwayModeChanged;
+
+ virtual void on(AwayModeChanged, AwayMode) noexcept { }
+ };
+
+ class ActivityManager : public Speaker, public Singleton, public TimerManagerListener
+ {
+ public:
+ ActivityManager();
+ ~ActivityManager();
+
+ void updateActivity(time_t aLastActivity = GET_TICK()) noexcept;
+
+ bool isAway() const noexcept { return awayMode != AWAY_OFF; }
+ AwayMode getAwayMode() const noexcept { return awayMode; }
+ void setAway(AwayMode aAway);
+
+ string getAwayMessage(const string& aAwayMsg, ParamMap& params) const noexcept;
+ private:
+ void on(TimerManagerListener::Second, uint64_t aTick) noexcept;
+
+ AwayMode awayMode;
+ time_t lastActivity = GET_TICK();
+ };
+
+} // namespace dcpp
+
+#endif // DCPLUSPLUS_DCPP_ACTIVITY_MANAGER_H
diff --git a/airdcpp-core/airdcpp/AdcHub.cpp b/airdcpp-core/airdcpp/AdcHub.cpp
index 4710e87b..90ac6e1f 100644
--- a/airdcpp-core/airdcpp/AdcHub.cpp
+++ b/airdcpp-core/airdcpp/AdcHub.cpp
@@ -19,6 +19,7 @@
#include "stdinc.h"
#include "version.h"
+#include "ActivityManager.h"
#include "AdcCommand.h"
#include "AdcHub.h"
#include "Message.h"
@@ -1436,7 +1437,7 @@ void AdcHub::infoImpl() {
addParam(lastInfoMap, c, "HO", Util::toString(counts[COUNT_OP]));
addParam(lastInfoMap, c, "VE", shortVersionString);
- addParam(lastInfoMap, c, "AW", AirUtil::getAway() ? "1" : Util::emptyString);
+ addParam(lastInfoMap, c, "AW", ActivityManager::getInstance()->isAway() ? "1" : Util::emptyString);
addParam(lastInfoMap, c, "LC", Localization::getCurrentLocale());
int64_t limit = ThrottleManager::getInstance()->getDownLimit() * 1000;
diff --git a/airdcpp-core/airdcpp/AirUtil.cpp b/airdcpp-core/airdcpp/AirUtil.cpp
index e4abfdc7..3208c348 100644
--- a/airdcpp-core/airdcpp/AirUtil.cpp
+++ b/airdcpp-core/airdcpp/AirUtil.cpp
@@ -19,20 +19,20 @@
#include "stdinc.h"
#include "AirUtil.h"
-#include "Util.h"
-#include "ThrottleManager.h"
+#include "ConnectivityManager.h"
#include "File.h"
+#include "LogManager.h"
#include "QueueManager.h"
-#include "SettingsManager.h"
-#include "ConnectivityManager.h"
#include "ResourceManager.h"
-#include "StringTokenizer.h"
+#include "SettingsManager.h"
+#include "ShareManager.h"
#include "SimpleXML.h"
#include "Socket.h"
-#include "LogManager.h"
-#include "Wildcards.h"
-#include "ShareManager.h"
+#include "StringTokenizer.h"
+#include "ThrottleManager.h"
+#include "Util.h"
+
#include
#include
@@ -63,9 +63,6 @@ boost::regex AirUtil::crcReg;
string AirUtil::privKeyFile;
string AirUtil::tempDLDir;
-AwayMode AirUtil::away = AWAY_OFF;
-time_t AirUtil::awayTime;
-
AirUtil::TimeCounter::TimeCounter(string aMsg) : start(GET_TICK()), msg(move(aMsg)) {
}
@@ -750,24 +747,6 @@ string AirUtil::regexEscape(const string& aStr, bool isWildcard) {
return result;
}
-void AirUtil::setAway(AwayMode aAway) {
- if(aAway != away)
- ClientManager::getInstance()->infoUpdated();
-
- if((aAway == AWAY_MANUAL) || (getAwayMode() == AWAY_MANUAL && aAway == AWAY_OFF) ) //only save the state if away mode is set by user
- SettingsManager::getInstance()->set(SettingsManager::AWAY, aAway > 0);
-
- away = aAway;
-
- if (away > AWAY_OFF)
- awayTime = time(NULL);
-}
-
-string AirUtil::getAwayMessage(const string& aAwayMsg, ParamMap& params) {
- params["idleTI"] = Util::formatSeconds(time(NULL) - awayTime);
- return Util::formatParams(aAwayMsg, params);
-}
-
string AirUtil::subtractCommonDirs(const string& toCompare, const string& toSubtract, char separator) {
if (toSubtract.length() > 3) {
string::size_type i = toSubtract.length()-2;
diff --git a/airdcpp-core/airdcpp/AirUtil.h b/airdcpp-core/airdcpp/AirUtil.h
index 8ec6fcea..3b45ffa7 100644
--- a/airdcpp-core/airdcpp/AirUtil.h
+++ b/airdcpp-core/airdcpp/AirUtil.h
@@ -26,14 +26,6 @@
namespace dcpp {
-//Away modes
-enum AwayMode : uint8_t {
- AWAY_OFF,
- AWAY_IDLE,
- AWAY_MINIMIZE,
- AWAY_MANUAL //highest value
-};
-
enum DupeType: uint8_t {
DUPE_NONE,
DUPE_SHARE_PARTIAL,
@@ -137,11 +129,6 @@ class AirUtil {
static string convertMovePath(const string& aPath, const string& aParent, const string& aTarget);
static string regexEscape(const string& aStr, bool isWildcard);
- static bool getAway() { return away > 0; }
- static AwayMode getAwayMode() { return away; }
- static void setAway(AwayMode aAway);
- static string getAwayMessage(const string& aAwayMsg, ParamMap& params);
-
/* Removes common dirs from the end of toSubtract */
static string subtractCommonDirs(const string& toCompare, const string& toSubtract, char separator);
@@ -151,8 +138,6 @@ class AirUtil {
private:
static bool removeDirectoryIfEmptyRe(const string& tgt, int maxAttempts, int curAttempts);
- static AwayMode away;
- static time_t awayTime;
};
diff --git a/airdcpp-core/airdcpp/AutoSearchManager.cpp b/airdcpp-core/airdcpp/AutoSearchManager.cpp
index a068ea7c..4bba9f60 100644
--- a/airdcpp-core/airdcpp/AutoSearchManager.cpp
+++ b/airdcpp-core/airdcpp/AutoSearchManager.cpp
@@ -54,20 +54,20 @@ AutoSearchManager::~AutoSearchManager() noexcept {
QueueManager::getInstance()->removeListener(this);
}
-void AutoSearchManager::logMessage(const string& aMsg, bool error) const noexcept {
- LogManager::getInstance()->message(STRING(AUTO_SEARCH) + ": " + aMsg, error ? LogMessage::SEV_ERROR : LogMessage::SEV_INFO);
+void AutoSearchManager::logMessage(const string& aMsg, LogMessage::Severity aSeverity) const noexcept {
+ LogManager::getInstance()->message(STRING(AUTO_SEARCH) + ": " + aMsg, aSeverity);
}
/* Adding new items for external use */
AutoSearchPtr AutoSearchManager::addAutoSearch(const string& ss, const string& aTarget, TargetUtil::TargetType aTargetType, bool isDirectory, AutoSearch::ItemType asType, bool aRemove, int aInterval) noexcept {
if (ss.length() <= 5) {
- logMessage(STRING_F(AUTOSEARCH_ADD_FAILED, ss % STRING(LINE_EMPTY_OR_TOO_SHORT)), true);
+ logMessage(STRING_F(AUTOSEARCH_ADD_FAILED, ss % STRING(LINE_EMPTY_OR_TOO_SHORT)), LogMessage::SEV_ERROR);
return nullptr;
}
auto lst = getSearchesByString(ss);
if (!lst.empty()) {
- logMessage(STRING_F(AUTOSEARCH_ADD_FAILED, ss % STRING(ITEM_NAME_EXISTS)), true);
+ logMessage(STRING_F(AUTOSEARCH_ADD_FAILED, ss % STRING(ITEM_NAME_EXISTS)), LogMessage::SEV_ERROR);
return nullptr;
}
@@ -97,7 +97,7 @@ void AutoSearchManager::addAutoSearch(AutoSearchPtr aAutoSearch, bool search, bo
if (search) {
if (!searchItem(aAutoSearch, TYPE_NEW)) {
//no hubs
- logMessage(CSTRING_F(AUTOSEARCH_ADDED, aAutoSearch->getSearchString()), false);
+ logMessage(CSTRING_F(AUTOSEARCH_ADDED, aAutoSearch->getSearchString()), LogMessage::SEV_INFO);
}
}
if(!loading) {
@@ -330,7 +330,7 @@ void AutoSearchManager::onRemoveBundle(const BundlePtr& aBundle, bool finished)
handleExpiredItems(expired);
for (auto& as : removed) {
removeAutoSearch(as);
- logMessage(STRING_F(COMPLETE_ITEM_X_REMOVED, as->getSearchString()), false);
+ logMessage(STRING_F(COMPLETE_ITEM_X_REMOVED, as->getSearchString()), LogMessage::SEV_INFO);
}
//One or more items got in searching state again
if (itemsEnabled)
@@ -341,10 +341,10 @@ void AutoSearchManager::onRemoveBundle(const BundlePtr& aBundle, bool finished)
void AutoSearchManager::handleExpiredItems(AutoSearchList& expired) noexcept{
for (auto& as : expired) {
if (SETTING(REMOVE_EXPIRED_AS)) {
- logMessage(STRING_F(EXPIRED_AS_REMOVED, as->getSearchString()), false);
+ logMessage(STRING_F(EXPIRED_AS_REMOVED, as->getSearchString()), LogMessage::SEV_INFO);
removeAutoSearch(as);
} else if (as->getEnabled()) {
- logMessage(STRING_F(EXPIRED_AS_DISABLED, as->getSearchString()), false);
+ logMessage(STRING_F(EXPIRED_AS_DISABLED, as->getSearchString()), LogMessage::SEV_INFO);
setItemActive(as, false);
} else {
// disabled already
@@ -449,7 +449,7 @@ void AutoSearchManager::performSearch(AutoSearchPtr& as, StringList& aHubs, Sear
msg = STRING_F(ITEM_SEARCHED_IN, searchWord % time);
}
}
- logMessage(msg, false);
+ logMessage(msg, LogMessage::SEV_INFO);
} else {
fire(AutoSearchManagerListener::SearchForeground(), as, searchWord);
}
@@ -850,11 +850,12 @@ void AutoSearchManager::handleAction(const SearchResultPtr& sr, AutoSearchPtr& a
} else {
TargetUtil::TargetInfo ti;
bool hasSpace = TargetUtil::getVirtualTarget(as->getTarget(), as->getTargetType(), ti, sr->getSize());
- if (!hasSpace)
- TargetUtil::reportInsufficientSize(ti, sr->getSize());
+ if (!hasSpace) {
+ logMessage(TargetUtil::formatSizeNotification(ti, sr->getSize()), LogMessage::SEV_WARNING);
+ }
try {
- auto b = QueueManager::getInstance()->createFileBundle(ti.targetDir + sr->getFileName(), sr->getSize(), sr->getTTH(),
+ auto b = QueueManager::getInstance()->createFileBundle(ti.getTarget() + sr->getFileName(), sr->getSize(), sr->getTTH(),
sr->getUser(), sr->getDate(), 0,
((as->getAction() == AutoSearch::ACTION_QUEUE) ? QueueItem::PAUSED : QueueItem::DEFAULT));
@@ -862,7 +863,7 @@ void AutoSearchManager::handleAction(const SearchResultPtr& sr, AutoSearchPtr& a
onBundleCreated(b, as->getToken());
}
} catch(const Exception& e) {
- onBundleError(as->getToken(), e.getError(), ti.targetDir + sr->getFileName(), sr->getUser());
+ onBundleError(as->getToken(), e.getError(), ti.getTarget() + sr->getFileName(), sr->getUser());
return;
}
}
@@ -881,7 +882,7 @@ void AutoSearchManager::handleAction(const SearchResultPtr& sr, AutoSearchPtr& a
if (as->getRemove()) {
removeAutoSearch(as);
- logMessage(STRING_F(COMPLETE_ITEM_X_REMOVED, as->getSearchString()), false);
+ logMessage(STRING_F(COMPLETE_ITEM_X_REMOVED, as->getSearchString()), LogMessage::SEV_INFO);
}
}
}
diff --git a/airdcpp-core/airdcpp/AutoSearchManager.h b/airdcpp-core/airdcpp/AutoSearchManager.h
index 904cdb9a..5cb2d96d 100644
--- a/airdcpp-core/airdcpp/AutoSearchManager.h
+++ b/airdcpp-core/airdcpp/AutoSearchManager.h
@@ -76,8 +76,7 @@ class AutoSearchManager : public Singleton, public SpeakergetQueueItems()) {
if (countAll || q->getDownloadedBytes() == 0) {
- s->second.queued += q->getSize();
+ s->second.addQueued(q->getSize());
}
}
}
diff --git a/airdcpp-core/airdcpp/CryptoManager.cpp b/airdcpp-core/airdcpp/CryptoManager.cpp
index 6e61f72a..83a335a8 100644
--- a/airdcpp-core/airdcpp/CryptoManager.cpp
+++ b/airdcpp-core/airdcpp/CryptoManager.cpp
@@ -54,11 +54,12 @@
namespace dcpp {
- void* CryptoManager::tmpKeysMap[KEY_LAST] = { NULL, NULL, NULL };
- CriticalSection* CryptoManager::cs = NULL;
- int CryptoManager::idxVerifyData = 0;
- char CryptoManager::idxVerifyDataName[] = "AirDC.VerifyData";
- CryptoManager::SSLVerifyData CryptoManager::trustedKeyprint = { false, "trusted_keyp" };
+void* CryptoManager::tmpKeysMap[KEY_LAST] = { NULL, NULL, NULL };
+CriticalSection* CryptoManager::cs = NULL;
+int CryptoManager::idxVerifyData = 0;
+char CryptoManager::idxVerifyDataName[] = "AirDC.VerifyData";
+CryptoManager::SSLVerifyData CryptoManager::trustedKeyprint = { false, "trusted_keyp" };
+
CryptoManager::CryptoManager()
:
@@ -90,47 +91,53 @@ CryptoManager::CryptoManager()
for (int i = KEY_RSA_2048; i != KEY_LAST; ++i)
tmpKeysMap[i] = getTmpRSA(getKeyLength(static_cast(i)));
- const char ciphersuites[] =
- "ECDHE-ECDSA-AES128-GCM-SHA256:"
- "ECDHE-RSA-AES128-GCM-SHA256:"
- "ECDHE-ECDSA-AES128-SHA256:"
- "ECDHE-RSA-AES128-SHA256:"
- "ECDHE-ECDSA-AES128-SHA:"
- "ECDHE-RSA-AES128-SHA:"
- "DHE-RSA-AES128-SHA:"
- "AES128-SHA:"
- "ECDHE-ECDSA-AES256-GCM-SHA384:"
- "ECDHE-RSA-AES256-GCM-SHA384:"
- "ECDHE-ECDSA-AES256-SHA384:"
- "ECDHE-RSA-AES256-SHA384:"
- "ECDHE-ECDSA-AES256-SHA:"
- "ECDHE-RSA-AES256-SHA:"
- "AES256-GCM-SHA384:"
- "AES256-SHA256:"
- "AES256-SHA";
-
SSL_CTX_set_options(clientContext, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION);
- SSL_CTX_set_cipher_list(clientContext, ciphersuites);
SSL_CTX_set_options(serverContext, SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION);
- SSL_CTX_set_cipher_list(serverContext, ciphersuites);
+
+ setContextOptions(clientContext, false);
+ setContextOptions(serverContext, true);
+
+ SSL_CTX_set_tmp_dh_callback(serverContext, CryptoManager::tmp_dh_cb);
+ SSL_CTX_set_tmp_rsa_callback(serverContext, CryptoManager::tmp_rsa_cb);
+ SSL_CTX_set_verify(clientContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback);
+ SSL_CTX_set_verify(serverContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback);
+ }
+}
+
+void CryptoManager::setContextOptions(SSL_CTX* aCtx, bool aServer) {
+ const char ciphersuites[] =
+ "ECDHE-ECDSA-AES128-GCM-SHA256:"
+ "ECDHE-RSA-AES128-GCM-SHA256:"
+ "ECDHE-ECDSA-AES128-SHA256:"
+ "ECDHE-RSA-AES128-SHA256:"
+ "ECDHE-ECDSA-AES128-SHA:"
+ "ECDHE-RSA-AES128-SHA:"
+ "DHE-RSA-AES128-SHA:"
+ "AES128-SHA:"
+ "ECDHE-ECDSA-AES256-GCM-SHA384:"
+ "ECDHE-RSA-AES256-GCM-SHA384:"
+ "ECDHE-ECDSA-AES256-SHA384:"
+ "ECDHE-RSA-AES256-SHA384:"
+ "ECDHE-ECDSA-AES256-SHA:"
+ "ECDHE-RSA-AES256-SHA:"
+ "AES256-GCM-SHA384:"
+ "AES256-SHA256:"
+ "AES256-SHA";
+
+ SSL_CTX_set_cipher_list(aCtx, ciphersuites);
#if OPENSSL_VERSION_NUMBER >= 0x1000201fL
- SSL_CTX_set1_curves_list(clientContext, "P-256");
- SSL_CTX_set1_curves_list(serverContext, "P-256");
+ SSL_CTX_set1_curves_list(aCtx, "P-256");
#endif
-
+
+ if (aServer) {
EC_KEY* tmp_ecdh;
if ((tmp_ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)) != NULL) {
- SSL_CTX_set_options(serverContext, SSL_OP_SINGLE_ECDH_USE);
- SSL_CTX_set_tmp_ecdh(serverContext, tmp_ecdh);
+ SSL_CTX_set_options(aCtx, SSL_OP_SINGLE_ECDH_USE);
+ SSL_CTX_set_tmp_ecdh(aCtx, tmp_ecdh);
EC_KEY_free(tmp_ecdh);
}
-
- SSL_CTX_set_tmp_dh_callback(serverContext, CryptoManager::tmp_dh_cb);
- SSL_CTX_set_tmp_rsa_callback(serverContext, CryptoManager::tmp_rsa_cb);
- SSL_CTX_set_verify(clientContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback);
- SSL_CTX_set_verify(serverContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback);
}
}
diff --git a/airdcpp-core/airdcpp/CryptoManager.h b/airdcpp-core/airdcpp/CryptoManager.h
index 52bb694b..7bbe5af8 100644
--- a/airdcpp-core/airdcpp/CryptoManager.h
+++ b/airdcpp-core/airdcpp/CryptoManager.h
@@ -69,6 +69,9 @@ class CryptoManager : public Singleton
static void setCertPaths();
static int idxVerifyData;
+
+ // Options that can also be shared with external contexts
+ static void setContextOptions(SSL_CTX* aSSL, bool aServer);
private:
friend class Singleton;
diff --git a/airdcpp-core/airdcpp/DCPlusPlus.cpp b/airdcpp-core/airdcpp/DCPlusPlus.cpp
index 1abb1fe6..f1b2cc6e 100644
--- a/airdcpp-core/airdcpp/DCPlusPlus.cpp
+++ b/airdcpp-core/airdcpp/DCPlusPlus.cpp
@@ -19,6 +19,7 @@
#include "stdinc.h"
#include "DCPlusPlus.h"
+#include "ActivityManager.h"
#include "ConnectionManager.h"
#include "DownloadManager.h"
#include "GeoManager.h"
@@ -105,6 +106,7 @@ void startup(function stepF, functionload(messageF);
@@ -186,6 +188,7 @@ void shutdown(function stepF, function progr
announce(STRING(SHUTTING_DOWN));
+ ActivityManager::deleteInstance();
ViewFileManager::deleteInstance();
HighlightManager::deleteInstance();
UpdateManager::deleteInstance();
diff --git a/airdcpp-core/airdcpp/DirectoryListing.cpp b/airdcpp-core/airdcpp/DirectoryListing.cpp
index b28fc2f9..b1d18ff0 100644
--- a/airdcpp-core/airdcpp/DirectoryListing.cpp
+++ b/airdcpp-core/airdcpp/DirectoryListing.cpp
@@ -42,7 +42,7 @@ namespace dcpp {
using boost::range::for_each;
using boost::range::find_if;
-DirectoryListing::DirectoryListing(const HintedUser& aUser, bool aPartial, const string& aFileName, bool aIsClientView, bool aIsOwnList) :
+DirectoryListing::DirectoryListing(const HintedUser& aUser, bool aPartial, const string& aFileName, bool aIsClientView, bool aIsOwnList) : TrackableDownloadItem(aIsOwnList || (!aPartial && !aFileName.empty())),
hintedUser(aUser), root(new Directory(nullptr, Util::emptyString, Directory::TYPE_INCOMPLETE_NOCHILD, 0)), partialList(aPartial), isOwnList(aIsOwnList), fileName(aFileName),
isClientView(aIsClientView), matchADL(SETTING(USE_ADLS) && !aPartial),
tasks(isClientView, Thread::NORMAL, std::bind(&DirectoryListing::dispatch, this, std::placeholders::_1))
@@ -110,6 +110,34 @@ void stripExtensions(string& name) noexcept {
}
}
+ProfileToken DirectoryListing::getShareProfile() const noexcept {
+ return Util::toInt(fileName);
+}
+
+void DirectoryListing::setShareProfile(ProfileToken aProfile) noexcept {
+ setFileName(Util::toString(aProfile));
+ if (partialList) {
+ addAsyncTask([=] {
+ changeDirectory(Util::emptyString, RELOAD_ALL);
+ });
+ } else {
+ addFullListTask(Util::emptyString);
+ }
+
+ SettingsManager::getInstance()->set(SettingsManager::LAST_LIST_PROFILE, aProfile);
+ fire(DirectoryListingListener::ShareProfileChanged());
+}
+
+void DirectoryListing::getPartialListInfo(int64_t& totalSize_, size_t& totalFiles_) const noexcept {
+ if (isOwnList) {
+ ShareManager::getInstance()->getProfileInfo(getShareProfile(), totalSize_, totalFiles_);
+ }
+
+ auto si = ClientManager::getInstance()->getShareInfo(hintedUser);
+ totalSize_ = si.first;
+ totalFiles_ = si.second;
+}
+
string DirectoryListing::getNickFromFilename(const string& fileName) noexcept {
// General file list name format: [username].[CID].[xml|xml.bz2]
@@ -506,7 +534,17 @@ int64_t DirectoryListing::getDirSize(const string& aDir) const noexcept {
}
bool DirectoryListing::viewAsText(const File::Ptr& aFile) const noexcept {
- return ViewFileManager::getInstance()->addFileNotify(aFile->getName(), aFile->getSize(), aFile->getTTH(), hintedUser, true);
+ if (isOwnList) {
+ StringList paths;
+ getLocalPaths(aFile, paths);
+ if (!paths.empty()) {
+ return ViewFileManager::getInstance()->addLocalFile(paths.front(), aFile->getTTH(), true);
+ }
+
+ return false;
+ }
+
+ return ViewFileManager::getInstance()->addUserFileNotify(aFile->getName(), aFile->getSize(), aFile->getTTH(), hintedUser, true);
}
DirectoryListing::Directory::Ptr DirectoryListing::findDirectory(const string& aName, const Directory::Ptr& current) const noexcept {
@@ -544,7 +582,7 @@ void DirectoryListing::findNfoImpl(const string& aPath, bool aAllowQueueList, Du
try {
SearchResultList results;
auto s = unique_ptr(SearchQuery::getSearch(Util::emptyString, Util::emptyString, 0, SearchManager::TYPE_ANY, SearchManager::SIZE_DONTCARE, { ".nfo" }, SearchQuery::MATCH_NAME, false, 10));
- ShareManager::getInstance()->search(results, *s.get(), Util::toInt(getFileName()), ClientManager::getInstance()->getMyCID(), Util::toAdcFile(aPath));
+ ShareManager::getInstance()->search(results, *s.get(), getShareProfile(), ClientManager::getInstance()->getMyCID(), Util::toAdcFile(aPath));
if (!results.empty()) {
auto paths = AirUtil::getDupePaths(DUPE_SHARE, results.front()->getTTH());
@@ -660,7 +698,7 @@ void DirectoryListing::getLocalPaths(const File::Ptr& f, StringList& ret) const
else
path = f->getParent()->getPath();
- ShareManager::getInstance()->getRealPaths(Util::toAdcFile(path + f->getName()), ret, Util::toInt(fileName));
+ ShareManager::getInstance()->getRealPaths(Util::toAdcFile(path + f->getName()), ret, getShareProfile());
} else {
ret = AirUtil::getDupePaths(f->getDupe(), f->getTTH());
}
@@ -677,7 +715,7 @@ void DirectoryListing::getLocalPaths(const Directory::Ptr& d, StringList& ret) c
path = d->getPath();
if (isOwnList) {
- ShareManager::getInstance()->getRealPaths(Util::toAdcFile(path), ret, Util::toInt(fileName));
+ ShareManager::getInstance()->getRealPaths(Util::toAdcFile(path), ret, getShareProfile());
} else {
ret = ShareManager::getInstance()->getDirPaths(path);
}
@@ -967,7 +1005,7 @@ void DirectoryListing::searchImpl(const string& aSearchString, int64_t aSize, in
if (isOwnList && partialList) {
SearchResultList results;
try {
- ShareManager::getInstance()->search(results, *curSearch, Util::toInt(fileName), CID(), aDir);
+ ShareManager::getInstance()->search(results, *curSearch, getShareProfile(), CID(), aDir);
} catch (...) {}
for (const auto& sr : results)
@@ -1055,6 +1093,10 @@ void DirectoryListing::loadPartialImpl(const string& aXml, const string& aBaseDi
}
}
+bool DirectoryListing::isLoaded() const noexcept {
+ return currentLocation.directory && !currentLocation.directory->getLoading();
+}
+
void DirectoryListing::matchQueueImpl() noexcept {
int matches = 0, newFiles = 0;
BundleList bundles;
@@ -1133,7 +1175,7 @@ void DirectoryListing::endSearch(bool timedOut /*false*/) noexcept {
}
int DirectoryListing::loadShareDirectory(const string& aPath, bool aRecurse) throw(Exception, AbortException) {
- auto mis = ShareManager::getInstance()->generatePartialList(Util::toAdcFile(aPath), aRecurse, Util::toInt(fileName));
+ auto mis = ShareManager::getInstance()->generatePartialList(Util::toAdcFile(aPath), aRecurse, getShareProfile());
if (mis) {
return loadXML(*mis, true, Util::toAdcFile(aPath));
}
@@ -1227,7 +1269,7 @@ void DirectoryListing::on(ShareManagerListener::DirectoriesRefreshed, uint8_t, c
string lastVirtual;
for (const auto& p : aPaths) {
- auto vPath = ShareManager::getInstance()->realToVirtual(p, Util::toInt(fileName));
+ auto vPath = ShareManager::getInstance()->realToVirtual(p, getShareProfile());
if (!vPath.empty() && lastVirtual != vPath && findDirectory(vPath)) {
addAsyncTask([=] { loadPartialImpl(Util::emptyString, vPath, false, false, nullptr); });
lastVirtual = vPath;
diff --git a/airdcpp-core/airdcpp/DirectoryListing.h b/airdcpp-core/airdcpp/DirectoryListing.h
index bbecdc68..0dcddefe 100644
--- a/airdcpp-core/airdcpp/DirectoryListing.h
+++ b/airdcpp-core/airdcpp/DirectoryListing.h
@@ -157,6 +157,7 @@ class DirectoryListing : public intrusive_ptr_base, public Use
~DirectoryListing();
void loadFile() throw(Exception, AbortException);
+ bool isLoaded() const noexcept;
//return the number of loaded dirs
int updateXML(const string& aXml, const string& aBase) throw(AbortException);
@@ -182,6 +183,10 @@ class DirectoryListing : public intrusive_ptr_base, public Use
string getNick(bool firstOnly) const noexcept;
static string getNickFromFilename(const string& fileName) noexcept;
static UserPtr getUserFromFilename(const string& fileName) noexcept;
+
+ ProfileToken getShareProfile() const noexcept;
+ void setShareProfile(ProfileToken aProfile) noexcept;
+ void getPartialListInfo(int64_t& totalSize_, size_t& totalFiles_) const noexcept;
const UserPtr& getUser() const noexcept { return hintedUser.user; }
const HintedUser& getHintedUser() const noexcept { return hintedUser; }
diff --git a/airdcpp-core/airdcpp/DirectoryListingListener.h b/airdcpp-core/airdcpp/DirectoryListingListener.h
index d6ca3ee1..efa9100a 100644
--- a/airdcpp-core/airdcpp/DirectoryListingListener.h
+++ b/airdcpp-core/airdcpp/DirectoryListingListener.h
@@ -42,6 +42,7 @@ class DirectoryListingListener {
typedef X<11> UserUpdated;
typedef X<12> StateChanged;
typedef X<13> Read;
+ typedef X<14> ShareProfileChanged;
virtual void on(LoadingFinished, int64_t /*start*/, const string& /*aDir*/, bool /*reloadList*/, bool /*changeDir*/) noexcept { }
virtual void on(LoadingFailed, const string&) noexcept { }
@@ -57,6 +58,7 @@ class DirectoryListingListener {
virtual void on(UserUpdated) noexcept {}
virtual void on(StateChanged) noexcept {}
virtual void on(Read) noexcept {}
+ virtual void on(ShareProfileChanged) noexcept {}
};
} // namespace dcpp
diff --git a/airdcpp-core/airdcpp/DirectoryListingManager.cpp b/airdcpp-core/airdcpp/DirectoryListingManager.cpp
index 98eea9d3..fe19a335 100644
--- a/airdcpp-core/airdcpp/DirectoryListingManager.cpp
+++ b/airdcpp-core/airdcpp/DirectoryListingManager.cpp
@@ -161,7 +161,7 @@ void DirectoryListingManager::processList(const string& aFileName, const string&
processListAction(dirList, aRemotePath, flags);
}
-bool DirectoryListingManager::download(const DirectoryDownloadInfo::Ptr& di, const DirectoryListingPtr& aList, const string& aTarget) noexcept {
+bool DirectoryListingManager::download(const DirectoryDownloadInfo::Ptr& di, const DirectoryListingPtr& aList, const string& aTarget, bool aHasFreeSpace) noexcept {
auto getList = [&] {
addDirectoryDownload(di->getListPath(), di->getBundleName(), aList->getHintedUser(), di->getTarget(), di->getTargetType(), di->getSizeUnknown(), di->getPriority(), di->getRecursiveListAttempted() ? true : false, di->getAutoSearch(), false, false);
};
@@ -182,7 +182,7 @@ bool DirectoryListingManager::download(const DirectoryDownloadInfo::Ptr& di, con
}
// Queue the directory
- return aList->downloadDirImpl(dir, aTarget + di->getBundleName() + PATH_SEPARATOR, di->getPriority(), di->getAutoSearch());
+ return aList->downloadDirImpl(dir, aTarget + di->getBundleName() + PATH_SEPARATOR, aHasFreeSpace ? di->getPriority() : QueueItemBase::PAUSED_FORCE, di->getAutoSearch());
}
void DirectoryListingManager::handleDownload(DirectoryDownloadInfo::Ptr& di, DirectoryListingPtr& aList) noexcept {
@@ -200,29 +200,30 @@ void DirectoryListingManager::handleDownload(DirectoryDownloadInfo::Ptr& di, Dir
}
if (directDownload) {
- download(di, aList, di->getTarget());
+ download(di, aList, di->getTarget(), true);
return;
}
//we have a new directory
TargetUtil::TargetInfo ti;
- int64_t dirSize = aList->getDirSize(di->getListPath());
+ auto dirSize = aList->getDirSize(di->getListPath());
TargetUtil::getVirtualTarget(di->getTarget(), di->getTargetType(), ti, dirSize);
- bool hasFreeSpace = ti.getFreeSpace() >= dirSize;
+ auto hasFreeSpace = ti.hasFreeSpace(dirSize);
if (di->getSizeUnknown()) {
- auto queued = download(di, aList, ti.targetDir);
- if (!hasFreeSpace && queued)
- TargetUtil::reportInsufficientSize(ti, dirSize);
+ auto queued = download(di, aList, ti.getTarget(), hasFreeSpace);
+ if (!hasFreeSpace && queued) {
+ LogManager::getInstance()->message(TargetUtil::formatSizeNotification(ti, dirSize), LogMessage::SEV_WARNING);
+ }
if (queued) {
WLock l(cs);
- finishedListings.emplace(di->getFinishedDirName(), new FinishedDirectoryItem(!hasFreeSpace, ti.targetDir));
+ finishedListings.emplace(di->getFinishedDirName(), new FinishedDirectoryItem(!hasFreeSpace, ti.getTarget()));
}
} else {
- if (download(di, aList, ti.targetDir)) {
+ if (download(di, aList, ti.getTarget(), true)) {
WLock l(cs);
- finishedListings.emplace(di->getFinishedDirName(), new FinishedDirectoryItem(false, ti.targetDir));
+ finishedListings.emplace(di->getFinishedDirName(), new FinishedDirectoryItem(false, ti.getTarget()));
}
}
}
@@ -362,17 +363,19 @@ void DirectoryListingManager::on(QueueManagerListener::Removed, const QueueItemP
void DirectoryListingManager::openOwnList(ProfileToken aProfile, bool useADL /*false*/) noexcept {
auto me = HintedUser(ClientManager::getInstance()->getMe(), Util::emptyString);
- if (hasList(me.user))
- return;
- auto dl = DirectoryListingPtr(new DirectoryListing(me, !useADL, Util::toString(aProfile), true, true));
- dl->setMatchADL(useADL);
+ auto dl = hasList(me.user);
+ if (dl) {
+ if (dl->getShareProfile() != aProfile) {
+ dl->setShareProfile(aProfile);
+ }
- {
- WLock l(cs);
- viewedLists[me] = dl;
+ return;
}
+ dl = createList(me, !useADL, Util::toString(aProfile), true);
+ dl->setMatchADL(useADL);
+
fire(DirectoryListingManagerListener::OpenListing(), dl, Util::emptyString, Util::emptyString);
}
@@ -380,14 +383,20 @@ void DirectoryListingManager::openFileList(const HintedUser& aUser, const string
if (hasList(aUser.user))
return;
- auto dl = DirectoryListingPtr(new DirectoryListing(aUser, false, aFile, true, false));
+ auto dl = createList(aUser, false, aFile, false);
+ fire(DirectoryListingManagerListener::OpenListing(), dl, Util::emptyString, Util::emptyString);
+}
+
+DirectoryListingPtr DirectoryListingManager::createList(const HintedUser& aUser, bool aPartial, const string& aFileName, bool aIsOwnList) noexcept {
+ auto dl = DirectoryListingPtr(new DirectoryListing(aUser, aPartial, aFileName, true, aIsOwnList));
{
WLock l(cs);
- viewedLists[aUser.user] = dl;
+ viewedLists[dl->getHintedUser()] = dl;
}
- fire(DirectoryListingManagerListener::OpenListing(), dl, Util::emptyString, Util::emptyString);
+ fire(DirectoryListingManagerListener::ListingCreated(), dl);
+ return dl;
}
void DirectoryListingManager::on(QueueManagerListener::Added, QueueItemPtr& aQI) noexcept {
@@ -402,19 +411,12 @@ void DirectoryListingManager::on(QueueManagerListener::Added, QueueItemPtr& aQI)
}
if (!aQI->isSet(QueueItem::FLAG_PARTIAL_LIST)) {
- dl = DirectoryListingPtr(new DirectoryListing(user, false, aQI->getListName(), true, false));
+ dl = createList(user, false, aQI->getListName(), false);
} else {
- dl = DirectoryListingPtr(new DirectoryListing(user, true, Util::emptyString, true, false));
+ dl = createList(user, true, Util::emptyString, false);
}
dl->onAddedQueue(aQI->getTarget());
-
- {
- WLock l(cs);
- viewedLists[user] = dl;
- }
-
- fire(DirectoryListingManagerListener::ListingCreated(), dl);
}
DirectoryListingPtr DirectoryListingManager::hasList(const UserPtr& aUser) noexcept {
diff --git a/airdcpp-core/airdcpp/DirectoryListingManager.h b/airdcpp-core/airdcpp/DirectoryListingManager.h
index 9812b363..d09c011c 100644
--- a/airdcpp-core/airdcpp/DirectoryListingManager.h
+++ b/airdcpp-core/airdcpp/DirectoryListingManager.h
@@ -109,9 +109,11 @@ namespace dcpp {
};
- bool download(const DirectoryDownloadInfo::Ptr& di, const DirectoryListingPtr& aList, const string& aTarget) noexcept;
+ bool download(const DirectoryDownloadInfo::Ptr& di, const DirectoryListingPtr& aList, const string& aTarget, bool aHasFreeSpace) noexcept;
void handleDownload(DirectoryDownloadInfo::Ptr& di, DirectoryListingPtr& aList) noexcept;
+ DirectoryListingPtr createList(const HintedUser& aUser, bool aPartial, const string& aFileName, bool aIsOwnList) noexcept;
+
friend class Singleton;
mutable SharedMutex cs;
diff --git a/airdcpp-core/airdcpp/File.cpp b/airdcpp-core/airdcpp/File.cpp
index 5c8c92dc..e3d54a1e 100644
--- a/airdcpp-core/airdcpp/File.cpp
+++ b/airdcpp-core/airdcpp/File.cpp
@@ -403,8 +403,7 @@ int File::extendFile(int64_t len) noexcept {
char zero;
if( (lseek(h, (off_t)len, SEEK_SET) != -1) && (::write(h, &zero,1) != -1) ) {
- ftruncate(h,(off_t)len);
- return 1;
+ return ftruncate(h,(off_t)len);
}
return -1;
}
diff --git a/airdcpp-core/airdcpp/HashManager.cpp b/airdcpp-core/airdcpp/HashManager.cpp
index 4d8749d2..de7035f4 100644
--- a/airdcpp-core/airdcpp/HashManager.cpp
+++ b/airdcpp-core/airdcpp/HashManager.cpp
@@ -1206,15 +1206,15 @@ int HashManager::Hasher::run() {
int64_t averageSpeed = 0;
if (!failed) {
- sizeHashed += size;
+ totalSizeHashed += size;
dirSizeHashed += size;
dirFilesHashed++;
- filesHashed++;
+ totalFilesHashed++;
}
if(end > start) {
- hashTime += (end - start);
+ totalHashTime += (end - start);
dirHashTime += (end - start);
averageSpeed = size * 1000 / (end - start);
}
@@ -1225,7 +1225,6 @@ int HashManager::Hasher::run() {
} else {
fi = HashedFile(tt.getRoot(), timestamp, size);
getInstance()->hashDone(fname, pathLower, tt, averageSpeed, fi, hasherID);
- //tth = tt.getRoot();
}
} catch(const FileException& e) {
totalBytesLeft -= sizeLeft;
@@ -1238,6 +1237,7 @@ int HashManager::Hasher::run() {
auto onDirHashed = [&] () -> void {
if ((SETTING(HASHERS_PER_VOLUME) == 1 || w.empty()) && (dirFilesHashed > 1 || !failed)) {
+ getInstance()->fire(HashManagerListener::DirectoryHashed(), initialDir, dirFilesHashed, dirSizeHashed, dirHashTime, hasherID);
if (dirFilesHashed == 1) {
getInstance()->log(STRING_F(HASHING_FINISHED_FILE, currentFile %
Util::formatBytes(dirSizeHashed) %
@@ -1252,7 +1252,7 @@ int HashManager::Hasher::run() {
}
}
- dirsHashed++;
+ totalDirsHashed++;
dirHashTime = 0;
dirSizeHashed = 0;
dirFilesHashed = 0;
@@ -1266,15 +1266,16 @@ int HashManager::Hasher::run() {
removeDevice(curDevID);
if (w.empty()) {
- if (sizeHashed > 0) {
- if (dirsHashed == 0) {
+ getInstance()->fire(HashManagerListener::HasherFinished(), totalDirsHashed, totalFilesHashed, totalSizeHashed, totalHashTime, hasherID);
+ if (totalSizeHashed > 0) {
+ if (totalDirsHashed == 0) {
onDirHashed();
//LogManager::getInstance()->message(STRING(HASHING_FINISHED_TOTAL_PLAIN), LogMessage::SEV_INFO);
} else {
onDirHashed();
- getInstance()->log(STRING_F(HASHING_FINISHED_TOTAL, filesHashed % Util::formatBytes(sizeHashed) % dirsHashed %
- Util::formatTime(hashTime / 1000, true) %
- (Util::formatBytes(hashTime > 0 ? ((sizeHashed * 1000) / hashTime) : 0) + "/s" )), hasherID, false, false);
+ getInstance()->log(STRING_F(HASHING_FINISHED_TOTAL, totalFilesHashed % Util::formatBytes(totalSizeHashed) % totalDirsHashed %
+ Util::formatTime(totalHashTime / 1000, true) %
+ (Util::formatBytes(totalHashTime > 0 ? ((totalSizeHashed * 1000) / totalHashTime) : 0) + "/s" )), hasherID, false, false);
}
} else if(!fname.empty()) {
//all files failed to hash?
@@ -1284,10 +1285,10 @@ int HashManager::Hasher::run() {
initialDir.clear();
}
- hashTime = 0;
- sizeHashed = 0;
- dirsHashed = 0;
- filesHashed = 0;
+ totalHashTime = 0;
+ totalSizeHashed = 0;
+ totalDirsHashed = 0;
+ totalFilesHashed = 0;
lastSpeed = 0;
deleteThis = hasherID != 0;
sfv.unload();
diff --git a/airdcpp-core/airdcpp/HashManager.h b/airdcpp-core/airdcpp/HashManager.h
index e0dc1506..7fd1e3f7 100644
--- a/airdcpp-core/airdcpp/HashManager.h
+++ b/airdcpp-core/airdcpp/HashManager.h
@@ -45,11 +45,15 @@ class HashManagerListener {
typedef X<1> HashFailed;
typedef X<2> MaintananceFinished;
typedef X<3> MaintananceStarted;
+ typedef X<4> DirectoryHashed;
+ typedef X<5> HasherFinished;
virtual void on(TTHDone, const string& /* filePath */, HashedFile& /* fileInfo */) noexcept { }
virtual void on(HashFailed, const string& /* filePath */, HashedFile& /*null*/) noexcept { }
virtual void on(MaintananceStarted) noexcept { }
virtual void on(MaintananceFinished) noexcept { }
+ virtual void on(DirectoryHashed, const string& /* dirPath */, int /* filesHashed */, int64_t /*sizeHashed*/, time_t /*hashDuration*/, int /*hasherId*/) noexcept { }
+ virtual void on(HasherFinished, int /* dirsHashed */, int /* filesHashed */, int64_t /*sizeHashed*/, time_t /*hashDuration*/, int /*hasherId*/) noexcept { }
};
class HashLoader;
@@ -183,13 +187,13 @@ class HashManager : public Singleton, public SpeakergetReplyTo()->getClient()->getHubUrl()), true);
chat->handleMessage(aMessage);
- if (AirUtil::getAway() && !myPM && (!SETTING(NO_AWAYMSG_TO_BOTS) || !user->isSet(User::BOT))) {
+ if (ActivityManager::getInstance()->isAway() && !myPM && (!SETTING(NO_AWAYMSG_TO_BOTS) || !user->isSet(User::BOT))) {
ParamMap params;
aMessage->getFrom()->getIdentity().getParams(params, "user", false);
string error;
- chat->sendMessage(AirUtil::getAwayMessage(c->get(HubSettings::AwayMsg), params), error, false);
+ chat->sendMessage(ActivityManager::getInstance()->getAwayMessage(c->get(HubSettings::AwayMsg), params), error, false);
}
}
diff --git a/airdcpp-core/airdcpp/NmdcHub.cpp b/airdcpp-core/airdcpp/NmdcHub.cpp
index 8263e33b..68865fe9 100644
--- a/airdcpp-core/airdcpp/NmdcHub.cpp
+++ b/airdcpp-core/airdcpp/NmdcHub.cpp
@@ -38,6 +38,7 @@
#include "ThrottleManager.h"
#include "UploadManager.h"
#include "MessageManager.h"
+#include "ActivityManager.h"
namespace dcpp {
@@ -987,7 +988,7 @@ void NmdcHub::myInfo(bool alwaysSend) {
version = VERSIONSTRING;
- if(AirUtil::getAway()) {
+ if(ActivityManager::getInstance()->isAway()) {
status |= Identity::AWAY;
}
if(!isActive()) {
diff --git a/airdcpp-core/airdcpp/PrivateChat.cpp b/airdcpp-core/airdcpp/PrivateChat.cpp
index 98f1256b..59d9c7a9 100644
--- a/airdcpp-core/airdcpp/PrivateChat.cpp
+++ b/airdcpp-core/airdcpp/PrivateChat.cpp
@@ -127,6 +127,7 @@ void PrivateChat::handleMessage(const ChatMessagePtr& aMessage) {
void PrivateChat::setRead() noexcept {
auto updated = cache.setRead();
if (updated > 0) {
+ sendPMInfo(PrivateChat::MSG_SEEN);
fire(PrivateChatListener::MessagesRead(), this);
}
}
diff --git a/airdcpp-core/airdcpp/QueueManager.h b/airdcpp-core/airdcpp/QueueManager.h
index 29ac104d..2a0d90fc 100644
--- a/airdcpp-core/airdcpp/QueueManager.h
+++ b/airdcpp-core/airdcpp/QueueManager.h
@@ -323,8 +323,11 @@ class QueueManager : public Singleton, public Speaker, public Speaker(aPath, aProfile, dirs);
+ RLock l(cs);
+ if (aPath == "/") {
+ boost::algorithm::copy_if(rootPaths | map_values, back_inserter(dirs), Directory::HasRootProfile(aProfile));
+ } else {
+ findVirtuals(aPath, aProfile, dirs);
+ }
if (aPath.back() == '/') {
- for(const auto& d: dirs)
+ // Directory
+ for (const auto& d : dirs) {
ret.push_back(d->getRealPath());
- } else { //its a file
+ }
+ } else {
+ // File
auto fileName = Text::toLower(Util::getAdcFileName(aPath));
for(const auto& d: dirs) {
auto it = d->files.find(fileName);
@@ -1721,7 +1728,6 @@ void ShareManager::getRootsByVirtual(const string& virtualName, ProfileToken aPr
}
void ShareManager::getRootsByVirtual(const string& virtualName, const ProfileTokenSet& aProfiles, Directory::List& dirs) const noexcept {
- RLock l(cs);
for(const auto& d: rootPaths | map_values) {
// Compare name
if (Util::stricmp(d->getProfileDir()->getNameLower(), virtualName) != 0) {
diff --git a/airdcpp-core/airdcpp/StringDefs.h b/airdcpp-core/airdcpp/StringDefs.h
index eeaa629f..035c3098 100644
--- a/airdcpp-core/airdcpp/StringDefs.h
+++ b/airdcpp-core/airdcpp/StringDefs.h
@@ -720,8 +720,8 @@ enum Strings { // @DontAdd
LOCK, // "Lock"
LOCK_TB, // "Lock toolbars"
LOG_COMBINE_ADC_PM, // "Use a single log file per CID for ADC users"
- LOG_CRC_OK, // "Show SFV check progress (CRC OK) in system log"
- LOG_HASHING, // "Show each hashed file in system log"
+ LOG_CRC_OK, // "Show SFV check progress (CRC OK)"
+ LOG_HASHING, // "Show each hashed file"
LOG_OFF, // "Log off"
LOG_SHARE_SCAN, // "Save the results to a log file when scanning the share"
LOG_SHARE_SCAN_PATH, // "Log filename (relative to the global log directory)"
@@ -1169,10 +1169,10 @@ enum Strings { // @DontAdd
RENAME_DLG_DESC, // "Rename also in the following profiles"
REPAIRING_X, // "Repairing %1%"
REPORT, // "Report user"
- REPORT_ALTERNATES, // "Show auto search for alternates in system log"
+ REPORT_ALTERNATES, // "Show auto search for alternates"
REPORT_DUPLICATE_FILES, // "Report duplicate files when generating file lists"
- REPORT_IGNORED, // "Report ignored and spam filtered chat messages in system log"
- REPORT_SKIPLIST, // "Show files blocked by the skiplist in system log"
+ REPORT_IGNORED, // "Report ignored and spam filtered chat messages"
+ REPORT_SKIPLIST, // "Show files blocked by the skiplist"
REQUESTING, // "Requesting"
REQUESTING_LIST, // "Requesting file list"
REQUIRED_BRACKETS, // "(required)"
@@ -1307,7 +1307,6 @@ enum Strings { // @DontAdd
SETTINGS_ARGUMENT, // "Arguments"
SETTINGS_AUTOPRIO, // "Auto priority settings"
SETTINGS_AUTOPRIO_FILES, // "Calculate priorities also for individual files"
- SETTINGS_AUTO_AWAY, // "Auto-away on minimize (and back on restore)"
SETTINGS_AUTO_BUNDLE_SEARCH, // "Automatically search for alternative bundle sources"
SETTINGS_AUTO_COMPLETE_BUNDLES, // "Try to complete bundles with missing files automatically"
SETTINGS_AUTO_DETECTION_USE_LIMITED, // "Use the limiter values when setting the auto detected speed and slot limits"
@@ -1409,7 +1408,7 @@ enum Strings { // @DontAdd
SETTINGS_LOG_FILELIST_TRANSFERS, // "Log file list transfers"
SETTINGS_LOG_MAIN_CHAT, // "Log main chat"
SETTINGS_LOG_PRIVATE_CHAT, // "Log private chat"
- SETTINGS_LOG_SCHEDULED_REFRESHES, // "Show scheduled file list refreshes in system log"
+ SETTINGS_LOG_SCHEDULED_REFRESHES, // "Show scheduled file list refreshes"
SETTINGS_LOG_STATUS_MESSAGES, // "Log status messages"
SETTINGS_LOG_SYSTEM_MESSAGES, // "Log system messages"
SETTINGS_LOG_UPLOADS, // "Log uploads"
@@ -1464,7 +1463,7 @@ enum Strings { // @DontAdd
SETTINGS_PUBLIC_HUB_LIST_URL, // "Public hubs list URL"
SETTINGS_QUEUE, // "Queue"
SETTINGS_RECENT_HOURS, // "The maximum age for a bundle dir to consider it as recent"
- SETTINGS_REPORT_ADDED_SOURCES, // "Report added sources in System Log"
+ SETTINGS_REPORT_ADDED_SOURCES, // "Show added bundle sources"
SETTINGS_REQUIRES_RESTART, // "Note; most of these options require that you restart AirDC++"
SETTINGS_RESET, // "Reset"
SETTINGS_SB_DIRTY_BLEND, // "Blending"
@@ -1643,8 +1642,8 @@ enum Strings { // @DontAdd
SWITCHING_TO_ADDRESS, // "Switching to the address %1%"
SYSTEM_DEFAULT, // "System default"
SYSTEM_LOG, // "System log"
- SYSTEM_SHOW_FINISHED_DOWNLOADS, // "Show finished downloads in system log"
- SYSTEM_SHOW_FINISHED_UPLOADS, // "Show finished uploads in system log"
+ SYSTEM_SHOW_FINISHED_DOWNLOADS, // "Show finished downloads"
+ SYSTEM_SHOW_FINISHED_UPLOADS, // "Show finished uploads"
TABS_ON_TOP, // "Tabs on top"
TAB_ACTIVE_BG, // "Active background"
TAB_ACTIVE_BORDER, // "Active border"
diff --git a/airdcpp-core/airdcpp/TargetUtil.cpp b/airdcpp-core/airdcpp/TargetUtil.cpp
index 99e83e82..43b43bf8 100644
--- a/airdcpp-core/airdcpp/TargetUtil.cpp
+++ b/airdcpp-core/airdcpp/TargetUtil.cpp
@@ -26,6 +26,8 @@
#ifdef _WIN32
#include
#include
+#else
+#include
#endif
namespace dcpp {
@@ -40,6 +42,7 @@ string TargetUtil::getMountPath(const string& aPath, const VolumeSet& aVolumes)
l = aPath.rfind(PATH_SEPARATOR, l-2);
if (l == string::npos || l <= 1)
break;
+
if (aVolumes.find(aPath.substr(0, l+1)) != aVolumes.end()) {
return aPath.substr(0, l+1);
}
@@ -57,13 +60,16 @@ string TargetUtil::getMountPath(const string& aPath, const VolumeSet& aVolumes)
}
}
}
+#else
+ // Return the root
+ return PATH_SEPARATOR_STR;
#endif
return Util::emptyString;
}
bool TargetUtil::getVirtualTarget(const string& aTarget, TargetUtil::TargetType targetType, TargetInfo& ti_, const int64_t& aSize) {
if (targetType == TARGET_PATH) {
- ti_.targetDir = aTarget;
+ ti_.setTarget(aTarget);
} else {
vector> dirList;
if (targetType == TARGET_FAVORITE) {
@@ -76,15 +82,15 @@ bool TargetUtil::getVirtualTarget(const string& aTarget, TargetUtil::TargetType
if (s != dirList.end()) {
const auto& targets = s->second;
bool tmp = getTarget(targets, ti_, aSize);
- if (!ti_.targetDir.empty()) {
+ if (ti_.hasTarget()) {
return tmp;
}
}
}
- if (ti_.targetDir.empty()) {
+ if (!ti_.hasTarget()) {
//failed to get the target, use the default one
- ti_.targetDir = SETTING(DOWNLOAD_DIRECTORY);
+ ti_.setTarget(SETTING(DOWNLOAD_DIRECTORY));
}
return getDiskInfo(ti_);
}
@@ -107,32 +113,33 @@ bool TargetUtil::getTarget(const StringList& targets, TargetInfo& retTi_, const
if (targetMap.empty()) {
//failed to get the volumes
if (!targets.empty()) {
- retTi_.targetDir = targets.front();
+ retTi_.setTarget(targets.front());
} else {
- retTi_.targetDir = SETTING(DOWNLOAD_DIRECTORY);
+ retTi_.setTarget(SETTING(DOWNLOAD_DIRECTORY));
}
- retTi_.diskSpace = File::getFreeSpace(retTi_.targetDir);
- return retTi_.getFreeSpace() >= aSize;
- }
-
- QueueManager::getInstance()->getDiskInfo(targetMap, volumes);
+ retTi_.setFreeDiskSpace(File::getFreeSpace(retTi_.getTarget()));
+ } else {
+ QueueManager::getInstance()->getDiskInfo(targetMap, volumes);
- compareMap(targetMap, retTi_, aSize, SETTING(DL_AUTOSELECT_METHOD));
- if (retTi_.targetDir.empty()) //no dir with enough space, choose the one with most space available
- compareMap(targetMap, retTi_, aSize, (int8_t)SettingsManager::SELECT_MOST_SPACE);
+ compareMap(targetMap, retTi_, aSize, SETTING(DL_AUTOSELECT_METHOD));
+ if (retTi_.getTarget().empty()) {
+ //no dir with enough space, choose the one with most space available
+ compareMap(targetMap, retTi_, aSize, (int8_t)SettingsManager::SELECT_MOST_SPACE);
+ }
+ }
- return retTi_.getFreeSpace() >= aSize;
+ return retTi_.hasFreeSpace(aSize);
}
void TargetUtil::compareMap(const TargetInfoMap& aTargetMap, TargetInfo& retTi_, const int64_t& aSize, int aMethod) {
for (auto mapTi: aTargetMap | map_values) {
if (aMethod == (int8_t)SettingsManager::SELECT_LEAST_SPACE) {
- int64_t diff = mapTi.getFreeSpace() - aSize;
- if (diff > 0 && (diff < (retTi_.getFreeSpace() - aSize) || !retTi_.isInitialized()))
+ int64_t diff = mapTi.getRealFreeSpace() - aSize;
+ if (diff > 0 && (diff < (retTi_.getRealFreeSpace() - aSize) || !retTi_.isInitialized()))
retTi_ = mapTi;
- } else if (mapTi.getFreeSpace() > retTi_.getFreeSpace() || !retTi_.isInitialized()) {
+ } else if (mapTi.getRealFreeSpace() > retTi_.getRealFreeSpace() || !retTi_.isInitialized()) {
retTi_ = mapTi;
}
}
@@ -141,16 +148,19 @@ void TargetUtil::compareMap(const TargetInfoMap& aTargetMap, TargetInfo& retTi_,
bool TargetUtil::getDiskInfo(TargetInfo& targetInfo_) {
VolumeSet volumes;
getVolumes(volumes);
- string pathVol = getMountPath(targetInfo_.targetDir, volumes);
+
+ auto pathVol = getMountPath(targetInfo_.getTarget(), volumes);
if (pathVol.empty()) {
return false;
}
- targetInfo_.diskSpace = File::getFreeSpace(pathVol);
+ targetInfo_.setFreeDiskSpace(File::getFreeSpace(pathVol));
TargetInfoMap targetMap;
targetMap[pathVol] = targetInfo_;
+ //LogManager::getInstance()->message("Target " + targetInfo_.targetDir + ", vol: " + pathVol + ", list " + Util::listToString(volumes) + ", space " + Util::formatBytes(targetInfo_.diskSpace), LogMessage::SEV_INFO);
+
QueueManager::getInstance()->getDiskInfo(targetMap, volumes);
targetInfo_ = targetMap[pathVol];
return true;
@@ -194,41 +204,50 @@ void TargetUtil::getVolumes(VolumeSet& volumes) {
++drive[0];
drives = (drives >> 1);
}
+#else
+ struct mntent *ent;
+ FILE *aFile;
+
+ aFile = setmntent("/proc/mounts", "r");
+ if (aFile == NULL) {
+ return;
+ }
+
+ while ((ent = getmntent(aFile)) != NULL) {
+ volumes.insert(Util::validatePath(ent->mnt_dir, true));
+ }
+ endmntent(aFile);
#endif
}
-void TargetUtil::reportInsufficientSize(const TargetInfo& ti, int64_t aSize) {
- string tmp;
- if (ti.queued > 0) {
- tmp = STRING(AUTO_SEARCH) + ": " + STRING_F(NOT_ENOUGH_SPACE_QUEUED_PAUSED,
- ti.targetDir %
- Util::formatBytes(ti.diskSpace) %
- Util::formatBytes(ti.queued) %
- Util::formatBytes(aSize));
- } else {
- tmp = STRING(AUTO_SEARCH) + ": " + STRING_F(NOT_ENOUGH_SPACE_PAUSED,
- ti.targetDir.c_str() %
- Util::formatBytes(ti.getFreeSpace()) %
+string TargetUtil::formatSizeNotification(const TargetInfo& ti, int64_t aSize) {
+ if (ti.getQueued() > 0) {
+ return STRING_F(NOT_ENOUGH_SPACE_QUEUED_PAUSED,
+ ti.getTarget() %
+ Util::formatBytes(ti.getFreeDiskSpace()) %
+ Util::formatBytes(ti.getQueued()) %
Util::formatBytes(aSize));
}
- LogManager::getInstance()->message(tmp, LogMessage::SEV_WARNING);
+
+ return STRING_F(NOT_ENOUGH_SPACE_PAUSED,
+ ti.getTarget() %
+ Util::formatBytes(ti.getRealFreeSpace()) %
+ Util::formatBytes(aSize));
}
-string TargetUtil::getInsufficientSizeMessage(const TargetInfo& ti, int64_t aSize) {
- string tmp;
- if (ti.queued > 0) {
- tmp = STRING_F(CONFIRM_SIZE_WARNING_QUEUE,
- Util::formatBytes(ti.queued).c_str() %
- ti.targetDir.c_str() %
- Util::formatBytes(ti.diskSpace).c_str() %
- Util::formatBytes(aSize).c_str());
- } else {
- tmp = STRING_F(CONFIRM_SIZE_WARNING,
- Util::formatBytes(ti.getFreeSpace()).c_str() %
- ti.targetDir.c_str() %
- Util::formatBytes(aSize).c_str());
+string TargetUtil::formatSizeConfirmation(const TargetInfo& ti, int64_t aSize) {
+ if (ti.getQueued() > 0) {
+ return STRING_F(CONFIRM_SIZE_WARNING_QUEUE,
+ Util::formatBytes(ti.getQueued()) %
+ ti.getTarget() %
+ Util::formatBytes(ti.getFreeDiskSpace()) %
+ Util::formatBytes(aSize));
}
- return tmp;
+
+ return STRING_F(CONFIRM_SIZE_WARNING,
+ Util::formatBytes(ti.getRealFreeSpace()) %
+ ti.getTarget() %
+ Util::formatBytes(aSize));
}
} //dcpp
\ No newline at end of file
diff --git a/airdcpp-core/airdcpp/TargetUtil.h b/airdcpp-core/airdcpp/TargetUtil.h
index 52253174..cd88f1d9 100644
--- a/airdcpp-core/airdcpp/TargetUtil.h
+++ b/airdcpp-core/airdcpp/TargetUtil.h
@@ -20,6 +20,8 @@
#define DCPLUSPLUS_DCPP_TARGET_UTIL_H
#include "typedefs.h"
+
+#include "GetSet.h"
#include "Util.h"
#include
@@ -30,19 +32,38 @@ using std::string;
class TargetUtil {
public:
- struct TargetInfo {
- explicit TargetInfo() : targetDir(Util::emptyString), diskSpace(0), queued(0) { }
- explicit TargetInfo(const string& aPath, int64_t aFreeSpace) : targetDir(aPath), diskSpace(aFreeSpace), queued(0) { }
+ class TargetInfo {
+ public:
+ explicit TargetInfo() { }
+ explicit TargetInfo(const string& aPath, int64_t aFreeSpace = 0) : target(aPath), freeDiskSpace(aFreeSpace) { }
- string targetDir;
- int64_t diskSpace, queued;
- int64_t getFreeSpace() const { return diskSpace-queued; }
- int64_t getDiff(int64_t aSize) const { return getFreeSpace() - aSize; }
- bool isInitialized() { return diskSpace != 0 || queued != 0 || !targetDir.empty(); }
+ int64_t getRealFreeSpace() const { return freeDiskSpace - queued; }
+ bool isInitialized() { return freeDiskSpace != 0 || queued != 0 || !target.empty(); }
bool operator<(const TargetInfo& ti) const {
- return (diskSpace-queued) < (ti.diskSpace-ti.queued);
+ return (freeDiskSpace - queued) < (ti.freeDiskSpace - ti.queued);
+ }
+
+ int64_t getQueued() const noexcept {
+ return queued;
+ }
+
+ bool hasTarget() const noexcept {
+ return !target.empty();
+ }
+
+ bool hasFreeSpace(int64_t aRequiredBytes) const noexcept {
+ return getRealFreeSpace() >= aRequiredBytes;
+ }
+
+ GETSET(string, target, Target);
+ IGETSET(int64_t, freeDiskSpace, FreeDiskSpace, 0);
+
+ void addQueued(int64_t aBytes) noexcept {
+ queued += aBytes;
}
+ private:
+ int64_t queued = 0;
};
enum TargetType {
@@ -65,8 +86,8 @@ class TargetUtil {
static bool getDiskInfo(TargetInfo& ti_);
static void compareMap(const TargetInfoMap& targets, TargetInfo& retTi_, const int64_t& aSize, int aMethod);
- static void reportInsufficientSize(const TargetInfo& ti, int64_t aSize);
- static string getInsufficientSizeMessage(const TargetInfo& ti, int64_t aSize);
+ static string formatSizeNotification(const TargetInfo& ti, int64_t aSize);
+ static string formatSizeConfirmation(const TargetInfo& ti, int64_t aSize);
};
}
diff --git a/airdcpp-core/airdcpp/TrackableDownloadItem.cpp b/airdcpp-core/airdcpp/TrackableDownloadItem.cpp
index d2ee6d1d..bc88eb0c 100644
--- a/airdcpp-core/airdcpp/TrackableDownloadItem.cpp
+++ b/airdcpp-core/airdcpp/TrackableDownloadItem.cpp
@@ -25,6 +25,12 @@
namespace dcpp {
+ TrackableDownloadItem::TrackableDownloadItem(bool aDownloaded) noexcept : state(aDownloaded ? STATE_DOWNLOADED : STATE_DOWNLOAD_PENDING) {
+ if (aDownloaded) {
+ timeFinished = GET_TIME();
+ }
+ }
+
TrackableDownloadItem::~TrackableDownloadItem() {
if (hasDownloads()) {
DownloadManager::getInstance()->removeListener(this);
@@ -68,6 +74,7 @@ namespace dcpp {
void TrackableDownloadItem::onRemovedQueue(const string& aPath, bool aFinished) noexcept {
if (aFinished) {
completedDownloads = true;
+ timeFinished = GET_TIME();
}
dcassert(completedDownloads);
diff --git a/airdcpp-core/airdcpp/TrackableDownloadItem.h b/airdcpp-core/airdcpp/TrackableDownloadItem.h
index 4ab01484..1102514a 100644
--- a/airdcpp-core/airdcpp/TrackableDownloadItem.h
+++ b/airdcpp-core/airdcpp/TrackableDownloadItem.h
@@ -32,6 +32,7 @@ namespace dcpp {
virtual void onRemovedQueue(const string& aDir, bool aFinished) noexcept;
virtual void onAddedQueue(const string& aDir) noexcept;
+ TrackableDownloadItem(bool aDownloaded) noexcept;
~TrackableDownloadItem() noexcept;
enum State : uint8_t {
@@ -50,6 +51,8 @@ namespace dcpp {
bool hasDownloads() const noexcept;
StringList getDownloads() const noexcept;
+
+ IGETSET(time_t, timeFinished, TimeFinished, 0);
protected:
virtual void onStateChanged() noexcept = 0;
diff --git a/airdcpp-core/airdcpp/ViewFile.cpp b/airdcpp-core/airdcpp/ViewFile.cpp
index 88d5a306..6010c9f8 100644
--- a/airdcpp-core/airdcpp/ViewFile.cpp
+++ b/airdcpp-core/airdcpp/ViewFile.cpp
@@ -23,18 +23,22 @@
#include "File.h"
namespace dcpp {
- ViewFile::ViewFile(const string& aTarget, const TTHValue& aTTH, bool aIsText, UpdateF&& aUpdateFunction) noexcept :
- path(aTarget), tth(aTTH), updateFunction(aUpdateFunction), text(aIsText) {
+ ViewFile::ViewFile(const string& aTarget, const TTHValue& aTTH, bool aIsText, bool aIsLocalFile, UpdateF&& aUpdateFunction) noexcept :
+ TrackableDownloadItem(aIsLocalFile), path(aTarget), tth(aTTH), updateFunction(aUpdateFunction), text(aIsText), localFile(aIsLocalFile) {
- onAddedQueue(path);
+ if (!aIsLocalFile) {
+ onAddedQueue(path);
+ }
}
ViewFile::~ViewFile() noexcept {
- File::deleteFile(path);
+ if (!localFile) {
+ File::deleteFile(path);
+ }
}
string ViewFile::getDisplayName() const noexcept {
- return AirUtil::fromOpenFileName(Util::getFileName(path));
+ return localFile ? Util::getFileName(path) : AirUtil::fromOpenFileName(Util::getFileName(path));
}
void ViewFile::onStateChanged() noexcept {
diff --git a/airdcpp-core/airdcpp/ViewFile.h b/airdcpp-core/airdcpp/ViewFile.h
index 9d2bea7a..1e94c128 100644
--- a/airdcpp-core/airdcpp/ViewFile.h
+++ b/airdcpp-core/airdcpp/ViewFile.h
@@ -29,7 +29,7 @@ namespace dcpp {
typedef std::function UpdateF;
public:
- ViewFile(const string& aTarget, const TTHValue& aTTH, bool aIsText, UpdateF&& aUpdateFunction) noexcept;
+ ViewFile(const string& aTarget, const TTHValue& aTTH, bool aIsText, bool aIsLocalFile, UpdateF&& aUpdateFunction) noexcept;
~ViewFile() noexcept;
const string& getPath() const noexcept {
@@ -42,12 +42,15 @@ namespace dcpp {
return text;
}
+ bool isLocalFile() const noexcept {
+ return localFile;
+ }
+
const TTHValue& getTTH() const noexcept {
return tth;
}
IGETSET(bool, read, Read, false);
- IGETSET(time_t, timeFinished, TimeFinished, 0);
protected:
void onStateChanged() noexcept;
private:
@@ -55,6 +58,7 @@ namespace dcpp {
const UpdateF updateFunction;
const TTHValue tth;
const bool text;
+ const bool localFile;
};
} // namespace dcpp
diff --git a/airdcpp-core/airdcpp/ViewFileManager.cpp b/airdcpp-core/airdcpp/ViewFileManager.cpp
index 4fd41848..cab94975 100644
--- a/airdcpp-core/airdcpp/ViewFileManager.cpp
+++ b/airdcpp-core/airdcpp/ViewFileManager.cpp
@@ -48,8 +48,6 @@ namespace dcpp {
auto file = getFile(aQI->getTTH());
if (file) {
- file->setTimeFinished(GET_TIME());
-
file->onRemovedQueue(aQI->getTarget(), true);
fire(ViewFileManagerListener::FileFinished(), file);
}
@@ -72,15 +70,20 @@ namespace dcpp {
return;
}
- auto file = make_shared(aQI->getTarget(), aQI->getTTH(), aQI->isSet(QueueItem::FLAG_TEXT),
+ createFile(aQI->getTarget(), aQI->getTTH(), aQI->isSet(QueueItem::FLAG_TEXT), false);
+ }
+
+ ViewFilePtr ViewFileManager::createFile(const string& aFileName, const TTHValue& aTTH, bool aIsText, bool aIsLocalFile) noexcept {
+ auto file = make_shared(aFileName, aTTH, aIsText, aIsLocalFile,
std::bind(&ViewFileManager::onFileUpdated, this, std::placeholders::_1));
{
WLock l(cs);
- viewFiles[aQI->getTTH()] = file;
+ viewFiles[aTTH] = file;
}
fire(ViewFileManagerListener::FileAdded(), file);
+ return file;
}
void ViewFileManager::onFileUpdated(const TTHValue& aTTH) noexcept {
@@ -113,8 +116,28 @@ namespace dcpp {
return p->second;
}
+
+ bool ViewFileManager::addLocalFile(const string& aPath, const TTHValue& aTTH, bool aIsText) noexcept {
+ if (getFile(aTTH)) {
+ return false;
+ }
+
+ auto file = createFile(aPath, aTTH, aIsText, true);
+
+ fire(ViewFileManagerListener::FileFinished(), file);
+ return true;
+ }
- bool ViewFileManager::addFileThrow(const string& aFileName, int64_t aSize, const TTHValue& aTTH, const HintedUser& aUser, bool aIsText) throw(QueueException, FileException) {
+ bool ViewFileManager::addUserFileThrow(const string& aFileName, int64_t aSize, const TTHValue& aTTH, const HintedUser& aUser, bool aIsText) throw(QueueException, FileException) {
+ if (aUser == ClientManager::getInstance()->getMe()) {
+ auto paths = ShareManager::getInstance()->getRealPaths(aTTH);
+ if (!paths.empty()) {
+ return addLocalFile(paths.front(), aTTH, aIsText);
+ }
+
+ return false;
+ }
+
if (getFile(aTTH)) {
return false;
}
@@ -123,9 +146,9 @@ namespace dcpp {
return true;
}
- bool ViewFileManager::addFileNotify(const string& aFileName, int64_t aSize, const TTHValue& aTTH, const HintedUser& aUser, bool aIsText) noexcept {
+ bool ViewFileManager::addUserFileNotify(const string& aFileName, int64_t aSize, const TTHValue& aTTH, const HintedUser& aUser, bool aIsText) noexcept {
try {
- if (ViewFileManager::getInstance()->addFileThrow(aFileName, aSize, aTTH, aUser, aIsText)) {
+ if (ViewFileManager::getInstance()->addUserFileThrow(aFileName, aSize, aTTH, aUser, aIsText)) {
return true;
}
diff --git a/airdcpp-core/airdcpp/ViewFileManager.h b/airdcpp-core/airdcpp/ViewFileManager.h
index 84ff1c63..de6ca890 100644
--- a/airdcpp-core/airdcpp/ViewFileManager.h
+++ b/airdcpp-core/airdcpp/ViewFileManager.h
@@ -42,16 +42,22 @@ namespace dcpp {
ViewFileMap getFiles() const noexcept;
// Adds the file and shows a notification in case of errors
- bool addFileNotify(const string& aFileName, int64_t aSize, const TTHValue& aTTH, const HintedUser& aUser, bool aIsText) noexcept;
+ // Can be used for viewing own files by TTH as well
+ bool addUserFileNotify(const string& aFileName, int64_t aSize, const TTHValue& aTTH, const HintedUser& aUser, bool aIsText) noexcept;
// Adds the file and throws if there are errors
- bool addFileThrow(const string& aFileName, int64_t aSize, const TTHValue& aTTH, const HintedUser& aUser, bool aIsText) throw(QueueException, FileException);
+ // Can be used for viewing own files by TTH as well
+ bool addUserFileThrow(const string& aFileName, int64_t aSize, const TTHValue& aTTH, const HintedUser& aUser, bool aIsText) throw(QueueException, FileException);
+
+ // Add a file by real path
+ bool addLocalFile(const string& aPath, const TTHValue& aTTH, bool aIsText) noexcept;
bool removeFile(const TTHValue& aTTH) noexcept;
ViewFilePtr getFile(const TTHValue& aTTH) const noexcept;
bool setRead(const TTHValue& aTTH) noexcept;
private:
+ ViewFilePtr createFile(const string& aFileName, const TTHValue& aTTH, bool aIsText, bool aIsLocalFile) noexcept;
static bool isViewedItem(const QueueItemPtr& aQI) noexcept;
void on(QueueManagerListener::Added, QueueItemPtr& aQI) noexcept;
diff --git a/airdcpp-webapi/api/CoreSettings.h b/airdcpp-webapi/api/CoreSettings.h
index ab0c6555..9c1da696 100644
--- a/airdcpp-webapi/api/CoreSettings.h
+++ b/airdcpp-webapi/api/CoreSettings.h
@@ -128,13 +128,11 @@ namespace webserver {
{ "max_hash_speed", SettingsManager::MAX_HASH_SPEED, ResourceManager::SETTINGS_MAX_HASHER_SPEED, ApiSettingItem::TYPE_GENERAL, { ResourceManager::Strings::MiB, true } },
{ "max_total_hashers", SettingsManager::MAX_HASHING_THREADS, ResourceManager::MAX_HASHING_THREADS },
{ "max_volume_hashers", SettingsManager::HASHERS_PER_VOLUME, ResourceManager::MAX_VOL_HASHERS },
- { "report_each_hashed_file", SettingsManager::LOG_HASHING, ResourceManager::LOG_HASHING },
//{ ResourceManager::REFRESH_OPTIONS },
{ "refresh_time", SettingsManager::AUTO_REFRESH_TIME, ResourceManager::SETTINGS_AUTO_REFRESH_TIME, ApiSettingItem::TYPE_GENERAL, { ResourceManager::Strings::MINUTES, false } },
{ "refresh_time_incoming", SettingsManager::INCOMING_REFRESH_TIME, ResourceManager::SETTINGS_INCOMING_REFRESH_TIME, ApiSettingItem::TYPE_GENERAL, { ResourceManager::Strings::MINUTES, false } },
{ "refresh_startup", SettingsManager::STARTUP_REFRESH, ResourceManager::SETTINGS_STARTUP_REFRESH },
- { "refresh_report_scheduled_refreshes", SettingsManager::LOG_SCHEDULED_REFRESHES, ResourceManager::SETTINGS_LOG_SCHEDULED_REFRESHES },
{ "refresh_threading", SettingsManager::REFRESH_THREADING, ResourceManager::MULTITHREADED_REFRESH },
//{ ResourceManager::SETTINGS_SHARING_OPTIONS },
@@ -145,8 +143,6 @@ namespace webserver {
{ "share_no_zero_byte", SettingsManager::NO_ZERO_BYTE, ResourceManager::SETTINGS_NO_ZERO_BYTE },
{ "share_max_size", SettingsManager::MAX_FILE_SIZE_SHARED, ResourceManager::DONT_SHARE_BIGGER_THAN, ApiSettingItem::TYPE_GENERAL, { ResourceManager::Strings::MiB, false } },
{ "share_follow_symlinks", SettingsManager::SHARE_FOLLOW_SYMLINKS, ResourceManager::FOLLOW_SYMLINKS },
- { "share_report_duplicates", SettingsManager::FL_REPORT_FILE_DUPES, ResourceManager::REPORT_DUPLICATE_FILES },
- { "share_report_skiplist", SettingsManager::REPORT_SKIPLIST, ResourceManager::REPORT_SKIPLIST },
//{ ResourceManager::SETTINGS_LOGGING },
{ "log_directory", SettingsManager::LOG_DIRECTORY, ResourceManager::SETTINGS_LOG_DIR, ApiSettingItem::TYPE_DIRECTORY_PATH },
@@ -171,6 +167,18 @@ namespace webserver {
{ "log_list_transfers", SettingsManager::LOG_FILELIST_TRANSFERS, ResourceManager::SETTINGS_LOG_FILELIST_TRANSFERS },
{ "single_log_per_cid", SettingsManager::PM_LOG_GROUP_CID, ResourceManager::LOG_COMBINE_ADC_PM },
+ // Events
+ { "report_uploads", SettingsManager::SYSTEM_SHOW_UPLOADS, ResourceManager::SYSTEM_SHOW_FINISHED_UPLOADS },
+ { "report_downloads", SettingsManager::SYSTEM_SHOW_DOWNLOADS, ResourceManager::SYSTEM_SHOW_FINISHED_DOWNLOADS },
+ { "report_search_alternates", SettingsManager::REPORT_ALTERNATES, ResourceManager::REPORT_ALTERNATES },
+ { "report_added_sources", SettingsManager::REPORT_ADDED_SOURCES, ResourceManager::SETTINGS_REPORT_ADDED_SOURCES },
+ { "report_share_skiplist", SettingsManager::REPORT_SKIPLIST, ResourceManager::REPORT_SKIPLIST },
+ { "report_hashed_files", SettingsManager::LOG_HASHING, ResourceManager::LOG_HASHING },
+ { "report_scheduled_refreshes", SettingsManager::LOG_SCHEDULED_REFRESHES, ResourceManager::SETTINGS_LOG_SCHEDULED_REFRESHES },
+ { "report_filelist_dupes", SettingsManager::FL_REPORT_FILE_DUPES, ResourceManager::REPORT_DUPLICATE_FILES },
+ { "report_ignored_messages", SettingsManager::LOG_IGNORED, ResourceManager::REPORT_IGNORED },
+ { "report_crc_ok", SettingsManager::LOG_CRC_OK, ResourceManager::LOG_CRC_OK },
+
//{ ResourceManager::HISTORIES },
{ "history_search_max", SettingsManager::HISTORY_SEARCH_MAX, ResourceManager::SEARCH_STRINGS },
{ "history_search_clear_exit", SettingsManager::HISTORY_SEARCH_CLEAR, ResourceManager::CLEAR_EXIT },
diff --git a/airdcpp-webapi/api/FilelistApi.cpp b/airdcpp-webapi/api/FilelistApi.cpp
index e3d666af..5eeb04b1 100644
--- a/airdcpp-webapi/api/FilelistApi.cpp
+++ b/airdcpp-webapi/api/FilelistApi.cpp
@@ -37,6 +37,7 @@ namespace webserver {
METHOD_HANDLER("session", Access::FILELISTS_EDIT, ApiRequest::METHOD_DELETE, (CID_PARAM), false, FilelistApi::handleDeleteList);
METHOD_HANDLER("session", Access::FILELISTS_EDIT, ApiRequest::METHOD_POST, (), true, FilelistApi::handlePostList);
+ METHOD_HANDLER("session", Access::FILELISTS_VIEW, ApiRequest::METHOD_POST, (EXACT_PARAM("me")), true, FilelistApi::handleOwnList);
METHOD_HANDLER("download_directory", Access::DOWNLOAD, ApiRequest::METHOD_POST, (), true, FilelistApi::handleDownload);
METHOD_HANDLER("find_nfo", Access::VIEW_FILES_EDIT, ApiRequest::METHOD_POST, (), true, FilelistApi::handleFindNfo);
@@ -92,6 +93,13 @@ namespace webserver {
return handleQueueList(aRequest, QueueItem::FLAG_CLIENT_VIEW);
}
+ api_return FilelistApi::handleOwnList(ApiRequest& aRequest) {
+ auto profile = JsonUtil::getField("share_profile", aRequest.getRequestBody());
+ DirectoryListingManager::getInstance()->openOwnList(profile);
+
+ return websocketpp::http::status_code::ok;
+ }
+
api_return FilelistApi::handleDeleteList(ApiRequest& aRequest) {
auto list = getSubModule(aRequest.getStringParam(0));
if (!list) {
@@ -135,12 +143,9 @@ namespace webserver {
}
json FilelistApi::serializeList(const DirectoryListingPtr& aList) noexcept {
- int64_t shareSize = -1, totalFiles = -1;
- auto user = ClientManager::getInstance()->findOnlineUser(aList->getHintedUser());
- if (user) {
- shareSize = Util::toInt64(user->getIdentity().getShareSize());
- totalFiles = Util::toInt64(user->getIdentity().getSharedFiles());
- }
+ int64_t totalSize = -1;
+ size_t totalFiles = -1;
+ aList->getPartialListInfo(totalSize, totalFiles);
return{
{ "id", aList->getUser()->getCID().toBase32() },
@@ -149,8 +154,9 @@ namespace webserver {
{ "location", FilelistInfo::serializeLocation(aList) },
{ "partial", aList->getPartialList() },
{ "total_files", totalFiles },
- { "total_size", shareSize },
- { "read", aList->isRead() }
+ { "total_size", totalSize },
+ { "read", aList->isRead() },
+ { "share_profile", aList->getIsOwnList() ? Serializer::serializeShareProfileSimple(aList->getShareProfile()) : json() },
};
}
diff --git a/airdcpp-webapi/api/FilelistApi.h b/airdcpp-webapi/api/FilelistApi.h
index 67781bdb..d2739275 100644
--- a/airdcpp-webapi/api/FilelistApi.h
+++ b/airdcpp-webapi/api/FilelistApi.h
@@ -45,6 +45,7 @@ namespace webserver {
api_return handlePostList(ApiRequest& aRequest);
api_return handleDeleteList(ApiRequest& aRequest);
+ api_return handleOwnList(ApiRequest& aRequest);
api_return handleGetLists(ApiRequest& aRequest);
api_return handleDownload(ApiRequest& aRequest);
diff --git a/airdcpp-webapi/api/FilelistInfo.cpp b/airdcpp-webapi/api/FilelistInfo.cpp
index 797085a8..8f356de5 100644
--- a/airdcpp-webapi/api/FilelistInfo.cpp
+++ b/airdcpp-webapi/api/FilelistInfo.cpp
@@ -63,7 +63,7 @@ namespace webserver {
dl->addListener(this);
- if (dl->hasCompletedDownloads()) {
+ if (dl->isLoaded()) {
updateItems(dl->getCurrentLocationInfo().directory->getPath());
}
}
@@ -100,7 +100,7 @@ namespace webserver {
string FilelistInfo::formatState(const DirectoryListingPtr& aList) noexcept {
if (aList->getDownloadState() == DirectoryListing::STATE_DOWNLOADED) {
- return !aList->getCurrentLocationInfo().directory || aList->getCurrentLocationInfo().directory->getLoading() ? "loading" : "loaded";
+ return aList->isLoaded() ? "loaded" : "loading";
}
return Serializer::serializeDownloadState(aList->getDownloadState());
@@ -200,6 +200,12 @@ namespace webserver {
});
}
+ void FilelistInfo::on(DirectoryListingListener::ShareProfileChanged) noexcept {
+ onSessionUpdated({
+ { "share_profile", Serializer::serializeShareProfileSimple(dl->getShareProfile()) }
+ });
+ }
+
void FilelistInfo::onSessionUpdated(const json& aData) noexcept {
if (!subscriptionActive("filelist_updated")) {
return;
diff --git a/airdcpp-webapi/api/FilelistInfo.h b/airdcpp-webapi/api/FilelistInfo.h
index 1b775463..5ce61e3b 100644
--- a/airdcpp-webapi/api/FilelistInfo.h
+++ b/airdcpp-webapi/api/FilelistInfo.h
@@ -118,6 +118,7 @@ namespace webserver {
void on(DirectoryListingListener::UserUpdated) noexcept;
void on(DirectoryListingListener::StateChanged) noexcept;
void on(DirectoryListingListener::Read) noexcept;
+ void on(DirectoryListingListener::ShareProfileChanged) noexcept;
void addListTask(CallBack&& aTask) noexcept;
diff --git a/airdcpp-webapi/api/HashApi.cpp b/airdcpp-webapi/api/HashApi.cpp
index 9e7f4eed..6ba1a080 100644
--- a/airdcpp-webapi/api/HashApi.cpp
+++ b/airdcpp-webapi/api/HashApi.cpp
@@ -39,8 +39,10 @@ namespace webserver {
createSubscription("hash_database_status");
createSubscription("hash_statistics");
+ createSubscription("hasher_directory_finished");
+ createSubscription("hasher_finished");
- timer->start();
+ timer->start(false);
}
HashApi::~HashApi() {
@@ -97,6 +99,30 @@ namespace webserver {
updateDbStatus(false);
}
+ void HashApi::on(HashManagerListener::DirectoryHashed, const string& aPath, int aFilesHashed, int64_t aSizeHashed, time_t aHashDuration, int aHasherId) noexcept {
+ maybeSend("hasher_directory_finished", [&] {
+ return json({
+ { "path", aPath },
+ { "size", aSizeHashed },
+ { "files", aFilesHashed },
+ { "duration", aHashDuration },
+ { "hasher_id", aHasherId },
+ });
+ });
+ }
+
+ void HashApi::on(HashManagerListener::HasherFinished, int aDirshashed, int aFilesHashed, int64_t aSizeHashed, time_t aHashDuration, int aHasherId) noexcept {
+ maybeSend("hasher_finished", [&] {
+ return json({
+ { "size", aSizeHashed },
+ { "files", aFilesHashed },
+ { "directories", aDirshashed },
+ { "duration", aHashDuration },
+ { "hasher_id", aHasherId },
+ });
+ });
+ }
+
void HashApi::updateDbStatus(bool aMaintenanceRunning) noexcept {
if (!subscriptionActive("hash_database_status"))
return;
diff --git a/airdcpp-webapi/api/HashApi.h b/airdcpp-webapi/api/HashApi.h
index 2c4f0278..421e0fd6 100644
--- a/airdcpp-webapi/api/HashApi.h
+++ b/airdcpp-webapi/api/HashApi.h
@@ -49,6 +49,9 @@ namespace webserver {
api_return handleOptimize(ApiRequest& aRequest);
api_return handleGetDbStatus(ApiRequest& aRequest);
+ void on(HashManagerListener::DirectoryHashed, const string& aPath, int aFilesHashed, int64_t aSizeHashed, time_t aHashDuration, int aHasherId) noexcept;
+ void on(HashManagerListener::HasherFinished, int aDirshashed, int aFilesHashed, int64_t aSizeHashed, time_t aHashDuration, int aHasherId) noexcept;
+
void on(HashManagerListener::MaintananceStarted) noexcept;
void on(HashManagerListener::MaintananceFinished) noexcept;
diff --git a/airdcpp-webapi/api/HierarchicalApiModule.h b/airdcpp-webapi/api/HierarchicalApiModule.h
index e63cf5c0..b5ad9876 100644
--- a/airdcpp-webapi/api/HierarchicalApiModule.h
+++ b/airdcpp-webapi/api/HierarchicalApiModule.h
@@ -237,6 +237,7 @@ namespace webserver {
// Ensure that we have a submodule (the parent must exist if we have a session)
auto m = aParentModule->getSubModule(aId);
if (!m) {
+ dcdebug("Trying to run an async task for a removed submodule\n");
return;
}
diff --git a/airdcpp-webapi/api/HubApi.cpp b/airdcpp-webapi/api/HubApi.cpp
index 85013e5f..4fa9442d 100644
--- a/airdcpp-webapi/api/HubApi.cpp
+++ b/airdcpp-webapi/api/HubApi.cpp
@@ -94,8 +94,7 @@ namespace webserver {
{ "hub_url", aClient->getHubUrl() },
{ "id", aClient->getClientId() },
{ "favorite_hub", aClient->getFavToken() },
- { "share_profile", aClient->getShareProfile() }
- //{ "share_profile", Serializer::serializeShare aClient->getShareProfile() },
+ { "share_profile", Serializer::serializeShareProfileSimple(aClient->getShareProfile()) }
};
Serializer::serializeCacheInfo(j, aClient->getCache(), Serializer::serializeUnreadChat);
diff --git a/airdcpp-webapi/api/HubInfo.cpp b/airdcpp-webapi/api/HubInfo.cpp
index e26082d7..972edc10 100644
--- a/airdcpp-webapi/api/HubInfo.cpp
+++ b/airdcpp-webapi/api/HubInfo.cpp
@@ -69,14 +69,14 @@ namespace webserver {
MessageManager::getInstance()->addListener(this);
client->addListener(this);
- timer->start();
-
METHOD_HANDLER("reconnect", Access::HUBS_EDIT, ApiRequest::METHOD_POST, (), false, HubInfo::handleReconnect);
METHOD_HANDLER("favorite", Access::HUBS_EDIT, ApiRequest::METHOD_POST, (), false, HubInfo::handleFavorite);
METHOD_HANDLER("password", Access::HUBS_EDIT, ApiRequest::METHOD_POST, (), true, HubInfo::handlePassword);
METHOD_HANDLER("redirect", Access::HUBS_EDIT, ApiRequest::METHOD_POST, (), false, HubInfo::handleRedirect);
METHOD_HANDLER("counts", Access::HUBS_VIEW, ApiRequest::METHOD_GET, (), false, HubInfo::handleGetCounts);
+
+ timer->start(false);
}
HubInfo::~HubInfo() {
diff --git a/airdcpp-webapi/api/SessionApi.cpp b/airdcpp-webapi/api/SessionApi.cpp
index cbe80b2e..ab5ac9ec 100644
--- a/airdcpp-webapi/api/SessionApi.cpp
+++ b/airdcpp-webapi/api/SessionApi.cpp
@@ -25,7 +25,9 @@
#include
#include
-#include
+#include
+#include
+#include
#include
namespace webserver {
@@ -80,8 +82,8 @@ namespace webserver {
{ "token", session->getAuthToken() },
{ "user", session->getUser()->getUserName() },
{ "system", getSystemInfo(aIp) },
- { "away_idle_time", SETTING(AWAY_IDLE_TIME) },
{ "run_wizard", SETTING(WIZARD_RUN) },
+ { "cid", ClientManager::getInstance()->getMyCID().toBase32() },
};
if (aSocket) {
@@ -93,7 +95,7 @@ namespace webserver {
return websocketpp::http::status_code::ok;
}
- api_return SessionApi::handleAway(ApiRequest& aRequest) {
+ api_return SessionApi::handleActivity(ApiRequest& aRequest) {
auto s = aRequest.getSession();
if (!s) {
aRequest.setResponseErrorStr("Not authorized");
@@ -101,13 +103,11 @@ namespace webserver {
}
if (!s->isUserSession()) {
- aRequest.setResponseErrorStr("Away state can only be changed for user sessions");
+ aRequest.setResponseErrorStr("Activity can only be updated for user sessions");
return websocketpp::http::status_code::bad_request;
}
- auto away = JsonUtil::getField("away", aRequest.getRequestBody());
- WebServerManager::getInstance()->getUserManager().setSessionAwayState(s->getId(), away);
-
+ ActivityManager::getInstance()->updateActivity();
return websocketpp::http::status_code::ok;
}
@@ -125,7 +125,7 @@ namespace webserver {
api_return SessionApi::handleSocketConnect(ApiRequest& aRequest, bool aIsSecure, const WebSocketPtr& aSocket) {
auto sessionToken = JsonUtil::getField("authorization", aRequest.getRequestBody(), false);
- SessionPtr session = WebServerManager::getInstance()->getUserManager().getSession(sessionToken);
+ auto session = WebServerManager::getInstance()->getUserManager().getSession(sessionToken);
if (!session) {
aRequest.setResponseErrorStr("Invalid session token");
return websocketpp::http::status_code::bad_request;
diff --git a/airdcpp-webapi/api/SessionApi.h b/airdcpp-webapi/api/SessionApi.h
index f5bb929a..3eb3fc66 100644
--- a/airdcpp-webapi/api/SessionApi.h
+++ b/airdcpp-webapi/api/SessionApi.h
@@ -31,7 +31,7 @@ namespace webserver {
api_return handleLogin(ApiRequest& aRequest, bool aIsSecure, const WebSocketPtr& aSocket, const string& aIp);
api_return handleSocketConnect(ApiRequest& aRequest, bool aIsSecure, const WebSocketPtr& aSocket);
api_return handleLogout(ApiRequest& aRequest);
- api_return handleAway(ApiRequest& aRequest);
+ api_return handleActivity(ApiRequest& aRequest);
json getSystemInfo(const string& aIp) const noexcept;
private:
diff --git a/airdcpp-webapi/api/ShareApi.cpp b/airdcpp-webapi/api/ShareApi.cpp
index daf94b3d..51e2c128 100644
--- a/airdcpp-webapi/api/ShareApi.cpp
+++ b/airdcpp-webapi/api/ShareApi.cpp
@@ -35,6 +35,7 @@ namespace webserver {
METHOD_HANDLER("refresh", Access::SETTINGS_EDIT, ApiRequest::METHOD_POST, (), false, ShareApi::handleRefreshShare);
METHOD_HANDLER("refresh", Access::SETTINGS_EDIT, ApiRequest::METHOD_POST, (EXACT_PARAM("paths")), true, ShareApi::handleRefreshPaths);
+ METHOD_HANDLER("refresh", Access::SETTINGS_EDIT, ApiRequest::METHOD_POST, (EXACT_PARAM("virtual")), true, ShareApi::handleRefreshVirtual);
}
ShareApi::~ShareApi() {
@@ -50,9 +51,29 @@ namespace webserver {
api_return ShareApi::handleRefreshPaths(ApiRequest& aRequest) {
auto paths = JsonUtil::getField("paths", aRequest.getRequestBody(), false);
+
auto ret = ShareManager::getInstance()->refreshPaths(paths);
+ if (ret == ShareManager::RefreshResult::REFRESH_PATH_NOT_FOUND) {
+ aRequest.setResponseErrorStr("Invalid paths were supplied");
+ return websocketpp::http::status_code::bad_request;
+ }
- //aRequest.setResponseBody(j);
+ return websocketpp::http::status_code::ok;
+ }
+
+ api_return ShareApi::handleRefreshVirtual(ApiRequest& aRequest) {
+ auto path = JsonUtil::getField("path", aRequest.getRequestBody(), false);
+ auto profile = JsonUtil::getField("profile", aRequest.getRequestBody());
+
+ StringList refreshPaths;
+ try {
+ ShareManager::getInstance()->getRealPaths(path, refreshPaths, profile);
+ } catch (const ShareException& e) {
+ aRequest.setResponseErrorStr(e.getError());
+ return websocketpp::http::status_code::bad_request;
+ }
+
+ ShareManager::getInstance()->refreshPaths(refreshPaths);
return websocketpp::http::status_code::ok;
}
diff --git a/airdcpp-webapi/api/ShareApi.h b/airdcpp-webapi/api/ShareApi.h
index 849dd26f..e44920f6 100644
--- a/airdcpp-webapi/api/ShareApi.h
+++ b/airdcpp-webapi/api/ShareApi.h
@@ -37,6 +37,7 @@ namespace webserver {
private:
api_return handleRefreshShare(ApiRequest& aRequest);
api_return handleRefreshPaths(ApiRequest& aRequest);
+ api_return handleRefreshVirtual(ApiRequest& aRequest);
api_return handleGetStats(ApiRequest& aRequest);
diff --git a/airdcpp-webapi/api/SystemApi.cpp b/airdcpp-webapi/api/SystemApi.cpp
index 2d0afa78..51595f5a 100644
--- a/airdcpp-webapi/api/SystemApi.cpp
+++ b/airdcpp-webapi/api/SystemApi.cpp
@@ -25,11 +25,11 @@
#include
#include
-#include
+#include
#include
namespace webserver {
- SystemApi::SystemApi(Session* aSession) : ApiModule(aSession, Access::ANY), timer(getTimer([this] { onTimer(); }, 500)) {
+ SystemApi::SystemApi(Session* aSession) : ApiModule(aSession, Access::ANY) {
METHOD_HANDLER("stats", Access::ANY, ApiRequest::METHOD_GET, (), false, SystemApi::handleGetStats);
@@ -37,32 +37,22 @@ namespace webserver {
METHOD_HANDLER("away", Access::ANY, ApiRequest::METHOD_POST, (), true, SystemApi::handleSetAway);
createSubscription("away_state");
- timer->start(true);
+
+ ActivityManager::getInstance()->addListener(this);
}
SystemApi::~SystemApi() {
- timer->stop(true);
+ ActivityManager::getInstance()->removeListener(this);
}
- void SystemApi::onTimer() noexcept {
- if (!subscriptionActive("away_state")) {
- return;
- }
-
- auto newState = serializeAwayState();
- if (newState == previousAway) {
- return;
- }
-
- previousAway = newState;
- send("away_state", newState);
+ void SystemApi::on(ActivityManagerListener::AwayModeChanged, AwayMode /*aNewMode*/) noexcept {
+ send("away_state", serializeAwayState());
}
- string SystemApi::getAwayState() noexcept {
- switch (AirUtil::getAwayMode()) {
+ string SystemApi::getAwayState(AwayMode aAwayMode) noexcept {
+ switch (aAwayMode) {
case AWAY_OFF: return "off";
case AWAY_MANUAL: return "manual";
- case AWAY_MINIMIZE:
case AWAY_IDLE: return "idle";
}
@@ -72,8 +62,7 @@ namespace webserver {
json SystemApi::serializeAwayState() noexcept {
return {
- { "state", getAwayState() },
- { "away_idle_time", SETTING(AWAY_IDLE_TIME) },
+ { "id", getAwayState(ActivityManager::getInstance()->getAwayMode()) },
};
}
@@ -84,7 +73,7 @@ namespace webserver {
api_return SystemApi::handleSetAway(ApiRequest& aRequest) {
auto away = JsonUtil::getField("away", aRequest.getRequestBody());
- AirUtil::setAway(away ? AWAY_MANUAL : AWAY_OFF);
+ ActivityManager::getInstance()->setAway(away ? AWAY_MANUAL : AWAY_OFF);
return websocketpp::http::status_code::ok;
}
diff --git a/airdcpp-webapi/api/SystemApi.h b/airdcpp-webapi/api/SystemApi.h
index 0f4d148c..0c8afbfd 100644
--- a/airdcpp-webapi/api/SystemApi.h
+++ b/airdcpp-webapi/api/SystemApi.h
@@ -20,11 +20,13 @@
#define DCPLUSPLUS_DCPP_SYSTEMAPI_H
#include
-
#include
+#include
+
+
namespace webserver {
- class SystemApi : public ApiModule {
+ class SystemApi : public ApiModule, private ActivityManagerListener {
public:
SystemApi(Session* aSession);
~SystemApi();
@@ -33,17 +35,15 @@ namespace webserver {
return 0;
}
private:
- static string getAwayState() noexcept;
+ static string getAwayState(AwayMode aAwayMode) noexcept;
static json serializeAwayState() noexcept;
- void onTimer() noexcept;
api_return handleGetAwayState(ApiRequest& aRequest);
api_return handleSetAway(ApiRequest& aRequest);
api_return handleGetStats(ApiRequest& aRequest);
- json previousAway;
- TimerPtr timer;
+ void on(ActivityManagerListener::AwayModeChanged, AwayMode aNewMode) noexcept;
};
}
diff --git a/airdcpp-webapi/api/TransferApi.cpp b/airdcpp-webapi/api/TransferApi.cpp
index 289806e5..aa208e06 100644
--- a/airdcpp-webapi/api/TransferApi.cpp
+++ b/airdcpp-webapi/api/TransferApi.cpp
@@ -34,7 +34,7 @@ namespace webserver {
METHOD_HANDLER("stats", Access::ANY, ApiRequest::METHOD_GET, (), false, TransferApi::handleGetStats);
createSubscription("transfer_statistics");
- timer->start();
+ timer->start(false);
}
TransferApi::~TransferApi() {
diff --git a/airdcpp-webapi/api/ViewFileApi.cpp b/airdcpp-webapi/api/ViewFileApi.cpp
index fab30664..e36c0e17 100644
--- a/airdcpp-webapi/api/ViewFileApi.cpp
+++ b/airdcpp-webapi/api/ViewFileApi.cpp
@@ -55,13 +55,13 @@ namespace webserver {
return{
{ "id", aFile->getTTH().toBase32() },
{ "tth", aFile->getTTH().toBase32() },
- //{ "path", aFile->getPath() },
{ "text", aFile->isText() },
{ "read", aFile->getRead() },
{ "name", aFile->getDisplayName() },
{ "state", Serializer::serializeDownloadState(aFile->getDownloadState()) },
{ "type", Serializer::serializeFileType(aFile->getPath()) },
{ "time_finished", aFile->getTimeFinished() },
+ { "downloaded", !aFile->isLocalFile() },
};
}
@@ -83,12 +83,12 @@ namespace webserver {
auto name = JsonUtil::getField("name", j, false);
auto size = JsonUtil::getField("size", j);
- auto user = Deserializer::deserializeHintedUser(j);
+ auto user = Deserializer::deserializeHintedUser(j, true);
auto isText = JsonUtil::getOptionalFieldDefault("text", j, false);
bool added = false;
try {
- added = ViewFileManager::getInstance()->addFileThrow(name, size, tth, user, isText);
+ added = ViewFileManager::getInstance()->addUserFileThrow(name, size, tth, user, isText);
} catch (const Exception& e) {
aRequest.setResponseErrorStr(e.getError());
return websocketpp::http::status_code::internal_server_error;
diff --git a/airdcpp-webapi/api/common/Deserializer.cpp b/airdcpp-webapi/api/common/Deserializer.cpp
index 756bc615..2c4b75d2 100644
--- a/airdcpp-webapi/api/common/Deserializer.cpp
+++ b/airdcpp-webapi/api/common/Deserializer.cpp
@@ -50,8 +50,9 @@ namespace webserver {
}
HintedUser Deserializer::deserializeHintedUser(const json& aJson, bool aAllowMe, const string& aFieldName) {
- auto user = JsonUtil::getRawValue(aFieldName, aJson);
- return HintedUser(deserializeUser(user), JsonUtil::getField("hub_url", user, false));
+ auto userJson = JsonUtil::getRawValue(aFieldName, aJson);
+ auto user = deserializeUser(userJson, aAllowMe);
+ return HintedUser(user, JsonUtil::getField("hub_url", userJson, aAllowMe && user == ClientManager::getInstance()->getMe()));
}
TTHValue Deserializer::deserializeTTH(const json& aJson) {
diff --git a/airdcpp-webapi/api/common/ListViewController.h b/airdcpp-webapi/api/common/ListViewController.h
index 48b4e8d3..82ec8e7d 100644
--- a/airdcpp-webapi/api/common/ListViewController.h
+++ b/airdcpp-webapi/api/common/ListViewController.h
@@ -278,7 +278,7 @@ namespace webserver {
if (!active) {
setActive(true);
updateList();
- timer->start();
+ timer->start(true);
}
return websocketpp::http::status_code::no_content;
@@ -329,7 +329,7 @@ namespace webserver {
if (paused && timer->isRunning()) {
timer->stop(false);
} else if (!paused && !timer->isRunning()) {
- timer->start();
+ timer->start(true);
}
}
diff --git a/airdcpp-webapi/api/common/Serializer.cpp b/airdcpp-webapi/api/common/Serializer.cpp
index bfb34731..b8c7b3f4 100644
--- a/airdcpp-webapi/api/common/Serializer.cpp
+++ b/airdcpp-webapi/api/common/Serializer.cpp
@@ -128,6 +128,18 @@ namespace webserver {
};
}
+ json Serializer::serializeShareProfileSimple(ProfileToken aProfile) noexcept {
+ auto sp = ShareManager::getInstance()->getShareProfile(aProfile);
+ if (!sp) {
+ return nullptr;
+ }
+
+ return {
+ { "id", sp->getToken() },
+ { "str", sp->getPlainName() },
+ };
+ }
+
json Serializer::serializeChatMessage(const ChatMessagePtr& aMessage) noexcept {
json ret = {
{ "id", aMessage->getId()},
diff --git a/airdcpp-webapi/api/common/Serializer.h b/airdcpp-webapi/api/common/Serializer.h
index 58cfb666..ee93e194 100644
--- a/airdcpp-webapi/api/common/Serializer.h
+++ b/airdcpp-webapi/api/common/Serializer.h
@@ -55,6 +55,8 @@ namespace webserver {
static json serializeIp(const string& aIP) noexcept;
static json serializeIp(const string& aIP, const string& aCountryCode) noexcept;
+ static json serializeShareProfileSimple(ProfileToken aProfile) noexcept;
+
static string getDownloadStateId(TrackableDownloadItem::State aState) noexcept;
static string getDownloadStateStr(TrackableDownloadItem::State aState) noexcept;
static json serializeDownloadState(TrackableDownloadItem::State aState) noexcept;
diff --git a/airdcpp-webapi/web-server/ApiRouter.cpp b/airdcpp-webapi/web-server/ApiRouter.cpp
index 856f9971..960bcbf8 100644
--- a/airdcpp-webapi/web-server/ApiRouter.cpp
+++ b/airdcpp-webapi/web-server/ApiRouter.cpp
@@ -149,8 +149,8 @@ namespace webserver {
}
} else if (aRequest.getStringParam(0) == "socket") {
return sessionApi.handleSocketConnect(aRequest, aIsSecure, aSocket);
- } else if (aRequest.getStringParam(0) == "away") {
- return sessionApi.handleAway(aRequest);
+ } else if (aRequest.getStringParam(0) == "activity") {
+ return sessionApi.handleActivity(aRequest);
}
aRequest.setResponseErrorStr("Invalid command");
diff --git a/airdcpp-webapi/web-server/Session.cpp b/airdcpp-webapi/web-server/Session.cpp
index bc57fa8d..e877c09e 100644
--- a/airdcpp-webapi/web-server/Session.cpp
+++ b/airdcpp-webapi/web-server/Session.cpp
@@ -52,7 +52,7 @@ namespace webserver {
Session::Session(WebUserPtr& aUser, const string& aToken, bool aIsSecure, WebServerManager* aServer, uint64_t maxInactivityMinutes, bool aIsUserSession) :
id(Util::rand()), user(aUser), token(aToken), started(GET_TICK()),
lastActivity(GET_TICK()), secure(aIsSecure), server(aServer),
- maxInactivity(maxInactivityMinutes*1000*60), userAway(!aIsUserSession), userSession(aIsUserSession) {
+ maxInactivity(maxInactivityMinutes*1000*60), userSession(aIsUserSession) {
ADD_MODULE("connectivity", ConnectivityApi);
ADD_MODULE("favorite_directories", FavoriteDirectoryApi);
@@ -103,6 +103,12 @@ namespace webserver {
}
void Session::onSocketConnected(const WebSocketPtr& aSocket) noexcept {
+ auto oldSocket = getServer()->getSocket(id);
+ if (oldSocket) {
+ oldSocket->debugMessage("Replace session socket");
+ oldSocket->close(websocketpp::close::status::policy_violation, "Another socket was connected to this session");
+ }
+
fire(SessionListener::SocketConnected(), aSocket);
}
diff --git a/airdcpp-webapi/web-server/Session.h b/airdcpp-webapi/web-server/Session.h
index b9210353..5d768182 100644
--- a/airdcpp-webapi/web-server/Session.h
+++ b/airdcpp-webapi/web-server/Session.h
@@ -60,7 +60,6 @@ namespace webserver {
Session(Session&) = delete;
Session& operator=(Session&) = delete;
- GETSET(bool, userAway, UserAway);
void onSocketConnected(const WebSocketPtr& aSocket) noexcept;
void onSocketDisconnected() noexcept;
diff --git a/airdcpp-webapi/web-server/Timer.h b/airdcpp-webapi/web-server/Timer.h
index 635f495c..df1afe45 100644
--- a/airdcpp-webapi/web-server/Timer.h
+++ b/airdcpp-webapi/web-server/Timer.h
@@ -41,21 +41,14 @@ namespace webserver {
stop(true);
}
- bool start(bool aInstantStart = true) {
+ bool start(bool aInstantTick) {
if (shutdown) {
return false;
}
running = true;
- timer.expires_from_now(aInstantStart ? boost::posix_time::milliseconds(0) : interval);
- timer.async_wait([this](const boost::system::error_code& error) {
- if (error == boost::asio::error::operation_aborted) {
- // Timer stopped, no calls to this if the timer has been destructed
- return;
- }
-
- tick();
- });
+ timer.expires_from_now(aInstantTick ? boost::posix_time::milliseconds(0) : interval);
+ timer.async_wait(std::bind(&Timer::tick, std::placeholders::_1, cbWrapper, this));
return true;
}
@@ -70,12 +63,17 @@ namespace webserver {
return running;
}
private:
- void tick() {
+ // Static in case the timer has been destructed
+ static void tick(const boost::system::error_code& error, const CallbackWrapper& cbWrapper, Timer* aTimer) {
+ if (error == boost::asio::error::operation_aborted) {
+ return;
+ }
+
if (cbWrapper) {
// We must ensure that the timer still exists when a new start call is performed
- cbWrapper(bind(&Timer::runTask, this));
+ cbWrapper(bind(&Timer::runTask, aTimer));
} else {
- runTask();
+ aTimer->runTask();
}
}
diff --git a/airdcpp-webapi/web-server/WebServerManager.cpp b/airdcpp-webapi/web-server/WebServerManager.cpp
index 66781d50..8014f641 100644
--- a/airdcpp-webapi/web-server/WebServerManager.cpp
+++ b/airdcpp-webapi/web-server/WebServerManager.cpp
@@ -21,13 +21,19 @@
#include
+#include
#include
#include
#include
+#include
#define CONFIG_NAME "WebServer.xml"
#define CONFIG_DIR Util::PATH_USER_CONFIG
+#define AUTHENTICATION_TIMEOUT 60 // seconds
+#define PING_INTERVAL 30 // seconds
+#define PONG_TIMEOUT 10 // seconds
+
#define HANDSHAKE_TIMEOUT 0 // disabled, affects HTTP downloads
#define DEFAULT_THREADS 4
@@ -82,7 +88,7 @@ namespace webserver {
void setEndpointLogSettings(T& aEndpoint, std::ostream& aStream) {
// Access
aEndpoint.set_access_channels(websocketpp::log::alevel::all);
- aEndpoint.clear_access_channels(websocketpp::log::alevel::frame_payload | websocketpp::log::alevel::frame_header);
+ aEndpoint.clear_access_channels(websocketpp::log::alevel::frame_payload | websocketpp::log::alevel::frame_header | websocketpp::log::alevel::control);
aEndpoint.get_alog().set_ostream(&aStream);
// Errors
@@ -90,6 +96,22 @@ namespace webserver {
aEndpoint.get_elog().set_ostream(&aStream);
}
+ template
+ void setEndpointHandlers(T& aEndpoint, bool aIsSecure, WebServerManager* aServer) {
+ aEndpoint.set_http_handler(
+ std::bind(&WebServerManager::on_http, aServer, &aEndpoint, _1, aIsSecure));
+ aEndpoint.set_message_handler(
+ std::bind(&WebServerManager::on_message, aServer, &aEndpoint, _1, _2, aIsSecure));
+
+ aEndpoint.set_close_handler(std::bind(&WebServerManager::on_close_socket, aServer, _1));
+ aEndpoint.set_open_handler(std::bind(&WebServerManager::on_open_socket, aServer, &aEndpoint, _1, aIsSecure));
+
+ aEndpoint.set_open_handshake_timeout(HANDSHAKE_TIMEOUT);
+
+ aEndpoint.set_pong_timeout(PONG_TIMEOUT * 1000);
+ aEndpoint.set_pong_timeout_handler(std::bind(&WebServerManager::onPongTimeout, aServer, _1, _2));
+ }
+
bool WebServerManager::start(ErrorF errorF, const string& aWebResourcePath) {
{
auto resourcePath = aWebResourcePath;
@@ -115,37 +137,21 @@ namespace webserver {
try {
// initialize asio with our external io_service rather than an internal one
endpoint_plain.init_asio(&ios);
-
- endpoint_plain.set_http_handler(
- std::bind(&WebServerManager::on_http, this, &endpoint_plain, _1, false));
- endpoint_plain.set_message_handler(
- std::bind(&WebServerManager::on_message, this, &endpoint_plain, _1, _2, false));
- endpoint_plain.set_close_handler(std::bind(&WebServerManager::on_close_socket, this, _1));
- endpoint_plain.set_open_handler(std::bind(&WebServerManager::on_open_socket, this, &endpoint_plain, _1, false));
-
- // Failures (plain)
- endpoint_plain.set_open_handshake_timeout(HANDSHAKE_TIMEOUT);
-
- // set up tls endpoint
endpoint_tls.init_asio(&ios);
- endpoint_tls.set_message_handler(
- std::bind(&WebServerManager::on_message, this, &endpoint_tls, _1, _2, true));
-
- endpoint_tls.set_close_handler(std::bind(&WebServerManager::on_close_socket, this, _1));
- endpoint_tls.set_open_handler(std::bind(&WebServerManager::on_open_socket, this, &endpoint_tls, _1, true));
- endpoint_tls.set_http_handler(std::bind(&WebServerManager::on_http, this, &endpoint_tls, _1, true));
-
- // Failures (TLS)
- endpoint_tls.set_open_handshake_timeout(HANDSHAKE_TIMEOUT);
-
- // TLS endpoint has an extra handler for the tls init
- endpoint_tls.set_tls_init_handler(std::bind(&WebServerManager::on_tls_init, this, _1));
+ //endpoint_plain.set_pong_handler(std::bind(&WebServerManager::onPongReceived, this, _1, _2));
} catch (const std::exception& e) {
errorF(e.what());
return false;
}
+ // Handlers
+ setEndpointHandlers(endpoint_plain, false, this);
+ setEndpointHandlers(endpoint_tls, true, this);
+
+ // TLS endpoint has an extra handler for the tls init
+ endpoint_tls.set_tls_init_handler(std::bind(&WebServerManager::on_tls_init, this, _1));
+
// Logging
setEndpointLogSettings(endpoint_plain, debugStreamPlain);
setEndpointLogSettings(endpoint_tls, debugStreamTls);
@@ -194,10 +200,66 @@ namespace webserver {
}
}
+ socketTimer = addTimer([this] { pingTimer(); }, PING_INTERVAL * 1000);
+ socketTimer->start(false);
+
fire(WebServerManagerListener::Started());
return hasServer;
}
+ WebSocketPtr WebServerManager::getSocket(websocketpp::connection_hdl hdl) const noexcept {
+ RLock l(cs);
+ auto s = sockets.find(hdl);
+ if (s != sockets.end()) {
+ return s->second;
+ }
+
+ return nullptr;
+ }
+
+ // For debugging only
+ void WebServerManager::onPongReceived(websocketpp::connection_hdl hdl, const string& aPayload) {
+ auto socket = getSocket(hdl);
+ if (!socket) {
+ return;
+ }
+
+ socket->debugMessage("PONG succeed");
+ }
+
+ void WebServerManager::onPongTimeout(websocketpp::connection_hdl hdl, const string& aPayload) {
+ auto socket = getSocket(hdl);
+ if (!socket) {
+ return;
+ }
+
+ socket->debugMessage("PONG timed out");
+
+ socket->close(websocketpp::close::status::internal_endpoint_error, "PONG timed out");
+ }
+
+ void WebServerManager::pingTimer() noexcept {
+ vector inactiveSockets;
+ auto tick = GET_TICK();
+
+ {
+ RLock l(cs);
+ for (const auto& socket : sockets | map_values) {
+ //socket->debugMessage("PING");
+ socket->ping();
+
+ // Disconnect sockets without a session after one minute
+ if (!socket->getSession() && socket->getTimeCreated() + AUTHENTICATION_TIMEOUT * 1000ULL < tick) {
+ inactiveSockets.push_back(socket);
+ }
+ }
+ }
+
+ for (const auto& s : inactiveSockets) {
+ s->close(websocketpp::close::status::policy_violation, "Authentication timeout");
+ }
+ }
+
context_ptr WebServerManager::on_tls_init(websocketpp::connection_hdl hdl) {
//std::cout << "on_tls_init called with hdl: " << hdl.lock().get() << std::endl;
context_ptr ctx(new boost::asio::ssl::context(boost::asio::ssl::context::tlsv12));
@@ -210,8 +272,9 @@ namespace webserver {
ctx->use_certificate_file(SETTING(TLS_CERTIFICATE_FILE), boost::asio::ssl::context::pem);
ctx->use_private_key_file(SETTING(TLS_PRIVATE_KEY_FILE), boost::asio::ssl::context::pem);
+
+ CryptoManager::setContextOptions(ctx->native_handle(), true);
} catch (std::exception& e) {
- //std::cout << e.what() << std::endl;
dcdebug("TLS init failed: %s", e.what());
}
@@ -226,6 +289,7 @@ namespace webserver {
}
void WebServerManager::stop() {
+ socketTimer->stop(true);
fire(WebServerManagerListener::Stopping());
if(endpoint_plain.is_listening())
@@ -307,6 +371,7 @@ namespace webserver {
sockets.erase(s);
}
+ dcdebug("Close socket: %s\n", socket->getSession() ? socket->getSession()->getAuthToken().c_str() : "(no session)");
if (socket->getSession()) {
socket->getSession()->onSocketDisconnected();
}
diff --git a/airdcpp-webapi/web-server/WebServerManager.h b/airdcpp-webapi/web-server/WebServerManager.h
index f05fe1da..16c59350 100644
--- a/airdcpp-webapi/web-server/WebServerManager.h
+++ b/airdcpp-webapi/web-server/WebServerManager.h
@@ -62,17 +62,10 @@ namespace webserver {
void on_message(EndpointType* aServer, websocketpp::connection_hdl hdl,
typename EndpointType::message_ptr msg, bool aIsSecure) {
- WebSocketPtr socket = nullptr;
-
- {
- WLock l(cs);
- auto s = sockets.find(hdl);
- if (s != sockets.end()) {
- socket = s->second;
- } else {
- dcassert(0);
- return;
- }
+ auto socket = getSocket(hdl);
+ if (!socket) {
+ dcassert(0);
+ return;
}
api.handleSocketRequest(msg->get_payload(), socket, aIsSecure);
@@ -80,7 +73,6 @@ namespace webserver {
template
void on_open_socket(EndpointType* aServer, websocketpp::connection_hdl hdl, bool aIsSecure) {
-
WLock l(cs);
auto socket = make_shared(aIsSecure, hdl, aServer);
sockets.emplace(hdl, socket);
@@ -88,6 +80,9 @@ namespace webserver {
void on_close_socket(websocketpp::connection_hdl hdl);
+ void onPongReceived(websocketpp::connection_hdl hdl, const string& aPayload);
+ void onPongTimeout(websocketpp::connection_hdl hdl, const string& aPayload);
+
template
void on_http(EndpointType* s, websocketpp::connection_hdl hdl, bool aIsSecure) {
// Blocking HTTP Handler
@@ -180,6 +175,7 @@ namespace webserver {
return serverThreads;
}
private:
+ WebSocketPtr getSocket(websocketpp::connection_hdl hdl) const noexcept;
bool listen(ErrorF& errorF);
bool initialize(ErrorF& errorF);
@@ -188,6 +184,7 @@ namespace webserver {
ServerConfig tlsServerConfig;
void loadServer(SimpleXML& xml_, const string& aTagName, ServerConfig& config_) noexcept;
+ void pingTimer() noexcept;
mutable SharedMutex cs;
@@ -197,6 +194,7 @@ namespace webserver {
context_ptr on_tls_init(websocketpp::connection_hdl hdl);
+ typedef vector WebSocketList;
std::map> sockets;
ApiRouter api;
@@ -204,6 +202,7 @@ namespace webserver {
unique_ptr userManager;
+ TimerPtr socketTimer;
bool has_io_service;
server_plain endpoint_plain;
diff --git a/airdcpp-webapi/web-server/WebSocket.cpp b/airdcpp-webapi/web-server/WebSocket.cpp
index bc871b6b..03430a42 100644
--- a/airdcpp-webapi/web-server/WebSocket.cpp
+++ b/airdcpp-webapi/web-server/WebSocket.cpp
@@ -19,12 +19,14 @@
#include
#include
+#include
#include
namespace webserver {
WebSocket::WebSocket(bool aIsSecure, websocketpp::connection_hdl aHdl) :
- secure(aIsSecure), hdl(aHdl) {
+ secure(aIsSecure), hdl(aHdl), timeCreated(GET_TICK()) {
+ debugMessage("Websocket created");
}
WebSocket::~WebSocket() {
@@ -41,7 +43,7 @@ namespace webserver {
}
}
- void WebSocket::sendApiResponse(const json& aResponseJson, const json& aErrorJson, websocketpp::http::status_code::value aCode, int aCallbackId) {
+ void WebSocket::sendApiResponse(const json& aResponseJson, const json& aErrorJson, websocketpp::http::status_code::value aCode, int aCallbackId) noexcept {
json j;
if (aCallbackId > 0) {
@@ -63,7 +65,11 @@ namespace webserver {
sendPlain(j.dump(4));
}
- void WebSocket::sendPlain(const string& aMsg) {
+ void WebSocket::debugMessage(const string& aMessage) const noexcept {
+ dcdebug(string(aMessage + " (%s)\n").c_str(), session ? session->getAuthToken().c_str() : "no session");
+ }
+
+ void WebSocket::sendPlain(const string& aMsg) noexcept {
//dcdebug("WebSocket::send: %s\n", aMsg.c_str());
try {
if (secure) {
@@ -73,7 +79,20 @@ namespace webserver {
}
} catch (const std::exception& e) {
- dcdebug("WebSocket::send failed: %s", e.what());
+ debugMessage("WebSocket::send failed: " + string(e.what()));
+ }
+ }
+
+ void WebSocket::ping() noexcept {
+ try {
+ if (secure) {
+ tlsServer->ping(hdl, Util::emptyString);
+ } else {
+ plainServer->ping(hdl, Util::emptyString);
+ }
+
+ } catch (const std::exception& e) {
+ debugMessage("WebSocket::ping failed: " + string(e.what()));
}
}
@@ -85,7 +104,7 @@ namespace webserver {
plainServer->close(hdl, aCode, aMsg);
}
} catch (const std::exception& e) {
- dcdebug("WebSocket::close failed: %s", e.what());
+ debugMessage("WebSocket::close failed: " + string(e.what()));
}
}
}
\ No newline at end of file
diff --git a/airdcpp-webapi/web-server/WebSocket.h b/airdcpp-webapi/web-server/WebSocket.h
index cdfc9c77..e245b939 100644
--- a/airdcpp-webapi/web-server/WebSocket.h
+++ b/airdcpp-webapi/web-server/WebSocket.h
@@ -43,13 +43,19 @@ namespace webserver {
IGETSET(SessionPtr, session, Session, nullptr);
- void sendPlain(const std::string& aMsg);
- void sendApiResponse(const json& aJsonResponse, const json& aErrorJson, websocketpp::http::status_code::value aCode, int aCallbackId);
+ void sendPlain(const std::string& aMsg) noexcept;
+ void sendApiResponse(const json& aJsonResponse, const json& aErrorJson, websocketpp::http::status_code::value aCode, int aCallbackId) noexcept;
WebSocket(WebSocket&) = delete;
WebSocket& operator=(WebSocket&) = delete;
string getIp() const noexcept;
+ void ping() noexcept;
+
+ void debugMessage(const string& aMessage) const noexcept;
+ time_t getTimeCreated() const noexcept {
+ return timeCreated;
+ }
protected:
WebSocket(bool aIsSecure, websocketpp::connection_hdl aHdl);
private:
@@ -61,6 +67,7 @@ namespace webserver {
websocketpp::connection_hdl hdl;
bool secure;
+ time_t timeCreated;
};
}
diff --git a/airdcpp-webapi/web-server/WebUserManager.cpp b/airdcpp-webapi/web-server/WebUserManager.cpp
index c8f42e1e..823a8953 100644
--- a/airdcpp-webapi/web-server/WebUserManager.cpp
+++ b/airdcpp-webapi/web-server/WebUserManager.cpp
@@ -23,7 +23,7 @@
#include
-#include
+#include
#include
#include
#include
@@ -70,36 +70,10 @@ namespace webserver {
}
if (aUserSession) {
- checkAwayState();
- }
- return session;
- }
-
- void WebUserManager::setSessionAwayState(LocalSessionId aSessionId, bool aAway) noexcept {
- auto s = getSession(aSessionId);
- if (!s) {
- return;
- }
-
- s->setUserAway(aAway);
- checkAwayState();
- }
-
- void WebUserManager::checkAwayState() noexcept {
- bool allAway = true;
- {
- RLock l(cs);
- allAway = boost::find_if(sessionsLocalId | map_values, [](const SessionPtr& aSession) {
- return !aSession->getUserAway();
- }).base() == sessionsLocalId.end();
+ ActivityManager::getInstance()->updateActivity();
}
- bool currentAway = AirUtil::getAwayMode() == AWAY_IDLE;
- if (allAway && !currentAway) {
- AirUtil::setAway(AWAY_IDLE);
- } else if (!allAway && currentAway) {
- AirUtil::setAway(AWAY_OFF);
- }
+ return session;
}
SessionPtr WebUserManager::getSession(const string& aSession) const noexcept {
@@ -162,10 +136,6 @@ namespace webserver {
sessionsRemoteId.erase(aSession->getAuthToken());
sessionsLocalId.erase(aSession->getId());
}
-
- if (aSession->isUserSession()) {
- checkAwayState();
- }
}
void WebUserManager::on(WebServerManagerListener::Started) noexcept {
diff --git a/airdcpp-webapi/web-server/WebUserManager.h b/airdcpp-webapi/web-server/WebUserManager.h
index b874f1cb..903a4eeb 100644
--- a/airdcpp-webapi/web-server/WebUserManager.h
+++ b/airdcpp-webapi/web-server/WebUserManager.h
@@ -56,9 +56,7 @@ namespace webserver {
StringList getUserNames() const noexcept;
size_t getSessionCount() const noexcept;
- void setSessionAwayState(LocalSessionId aSessionId, bool aAway) noexcept;
private:
- void checkAwayState() noexcept;
mutable SharedMutex cs;
std::map users;
diff --git a/airdcppd/Client.cpp b/airdcppd/Client.cpp
index 3d93be4d..45bda89e 100644
--- a/airdcppd/Client.cpp
+++ b/airdcppd/Client.cpp
@@ -21,7 +21,7 @@
#include
#include
-#include
+#include
#include
#include
#include
@@ -95,7 +95,7 @@ bool Client::startup() {
return false;
}
- AirUtil::setAway(AWAY_IDLE);
+ ActivityManager::getInstance()->setAway(AWAY_IDLE);
SettingsManager::getInstance()->setDefault(SettingsManager::LOG_IGNORED, false);
SettingsManager::getInstance()->setDefault(SettingsManager::NICK, getDefaultNick());
diff --git a/airdcppd/main.cpp b/airdcppd/main.cpp
index 9ddc201e..63c6c725 100755
--- a/airdcppd/main.cpp
+++ b/airdcppd/main.cpp
@@ -145,16 +145,20 @@ static void installHandler() {
#include
static void daemonize() {
+ auto reportError = [](const char* aMessage) {
+ fprintf(stderr, (string(aMessage) + ": %s\n").c_str(), strerror(errno));
+ };
+
switch(fork()) {
case -1:
- fprintf(stderr, "First fork failed: %s\n", strerror(errno));
+ reportError("First fork failed");
exit(5);
case 0: break;
default: _exit(0);
}
if(setsid() < 0) {
- fprintf(stderr, "setsid failed: %s\n", strerror(errno));
+ reportError("setsid failed");
exit(6);
}
@@ -166,12 +170,26 @@ static void daemonize() {
default: exit(0);
}
- chdir("/");
+ if (chdir("/") < 0) {
+ reportError("chdir failed");
+ exit(8);
+ }
+
close(0);
close(1);
close(2);
+
open("/dev/null", O_RDWR);
- dup(0); dup(0);
+
+ if (dup(0) < 0) {
+ reportError("dup failed for stdout");
+ exit(9);
+ }
+
+ if (dup(0) < 0) {
+ reportError("dup failed for stderr");
+ exit(10);
+ }
}
#include