diff --git a/src/account.h b/src/account.h index 9453511be157438455e9b6794f5fcd622bef2ce5..1b56003a90932a434979d1c93d27982a1de3de5a 100644 --- a/src/account.h +++ b/src/account.h @@ -301,6 +301,13 @@ class Account : public Serializable, public std::enable_shared_from_this<Account */ virtual void connectivityChanged() {}; + public: // virtual methods that has to be implemented by concrete classes + /** + * This method is called to request removal of possible account traces on the system, + * like internal account setup files. + */ + virtual void flush() { /* nothing to do here - overload */ }; + private: NON_COPYABLE(Account); diff --git a/src/client/configurationmanager.cpp b/src/client/configurationmanager.cpp index 1462b6350fc99f8207f7e08da56254570f25b9a9..44d4a2bd771883866aae1ae4b17f84d5d97727e9 100644 --- a/src/client/configurationmanager.cpp +++ b/src/client/configurationmanager.cpp @@ -343,7 +343,7 @@ addAccount(const std::map<std::string, std::string>& details) void removeAccount(const std::string& accountID) { - return ring::Manager::instance().removeAccount(accountID); + return ring::Manager::instance().removeAccount(accountID, true); // with 'flush' enabled } std::vector<std::string> diff --git a/src/fileutils.cpp b/src/fileutils.cpp index 28961bc3e02d931653bfd52ef9af2fb15f613b41..707df11a545d949bab671b1974fd805812e9247a 100644 --- a/src/fileutils.cpp +++ b/src/fileutils.cpp @@ -24,8 +24,8 @@ #include "config.h" #endif -#include "fileutils.h" #include "logger.h" +#include "fileutils.h" #include "compiler_intrinsics.h" #ifdef __APPLE__ @@ -222,6 +222,20 @@ bool isDirectoryWritable(const std::string &directory) return access(directory.c_str(), W_OK) == 0; } +bool isSymLink(const std::string& path) +{ +#ifndef _WIN32 + struct stat s; + if (lstat(path.c_str(), &s) == 0) + return S_ISLNK(s.st_mode); +#else + DWORD attr = GetFileAttributes(ring::to_wstring(path).c_str()); + if (attr & FILE_ATTRIBUTE_REPARSE_POINT) + return true; +#endif + return false; +} + std::chrono::system_clock::time_point writeTime(const std::string& path) { @@ -511,4 +525,19 @@ recursive_mkdir(const std::string& path, mode_t mode) return true; } +int +removeAll(const std::string& path) +{ + if (path.empty()) + return -1; + if (isDirectory(path) and !isSymLink(path)) { + auto dir = path; + if (dir.back() != DIR_SEPARATOR_CH) + dir += DIR_SEPARATOR_CH; + for (auto& entry : fileutils::readDirectory(dir)) + removeAll(dir + entry); + } + return remove(path); +} + }} // namespace ring::fileutils diff --git a/src/fileutils.h b/src/fileutils.h index ef7ea8bbf94dcf1c937f28a5b42e6431596faa26..25bb3ae0a91d439965660fdc45b2d150228c6a43 100644 --- a/src/fileutils.h +++ b/src/fileutils.h @@ -24,6 +24,7 @@ #include <string> #include <vector> #include <chrono> +#include <cstdio> #define PROTECTED_GETENV(str) ({char *envvar_ = getenv((str)); \ envvar_ ? envvar_ : "";}) @@ -67,6 +68,8 @@ namespace ring { namespace fileutils { bool isDirectory(const std::string& path); + bool isSymLink(const std::string& path); + std::chrono::system_clock::time_point writeTime(const std::string& path); /** @@ -87,6 +90,17 @@ namespace ring { namespace fileutils { }; FileHandle create_pidfile(); + /** + * Direct binding on std::remove, with std::string as argument + */ + static inline int remove(const std::string& path) { return std::remove(path.c_str()); } + + /** + * Prune given directory's content and remove it, symlinks are not followed. + * Return 0 if succeed, -1 if directory is not removed (content can be removed partially). + */ + int removeAll(const std::string& path); + }} // namespace ring::fileutils #endif // FILEUTILS_H_ diff --git a/src/manager.cpp b/src/manager.cpp index bb863b7171a2f01b9c79b10de92eb3074ed82f5c..9bb9014014a0193f4e8c5465c2ba72baeeea5bcc 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -2510,11 +2510,13 @@ void Manager::removeAccounts() removeAccount(acc); } -void Manager::removeAccount(const std::string& accountID) +void Manager::removeAccount(const std::string& accountID, bool flush) { // Get it down and dying if (const auto& remAccount = getAccount(accountID)) { remAccount->doUnregister(); + if (flush) + remAccount->flush(); accountFactory_.removeAccount(*remAccount); } diff --git a/src/manager.h b/src/manager.h index 166bdc67ac9f28274e023f491d14bf48f099f4cf..34c4ebb9964ef0cf02b158e7c65c00cfdb529c3d 100644 --- a/src/manager.h +++ b/src/manager.h @@ -514,9 +514,10 @@ class Manager { /** * Delete an existing account, unregister VoIPLink associated, and * purge from configuration. + * If 'flush' argument is true, filesystem entries are also removed. * @param accountID The account unique ID */ - void removeAccount(const std::string& accountID); + void removeAccount(const std::string& accountID, bool flush=false); /** * Set input audio plugin diff --git a/src/ringdht/ringaccount.cpp b/src/ringdht/ringaccount.cpp index baa24b5dc5a74705ef50642dba1e667e6eb68c45..c83d75eb54f97ebf282737c25be5f29a794a73f1 100644 --- a/src/ringdht/ringaccount.cpp +++ b/src/ringdht/ringaccount.cpp @@ -152,6 +152,17 @@ RingAccount::~RingAccount() dht_.join(); } +void +RingAccount::flush() +{ + // Class base method + SIPAccountBase::flush(); + + fileutils::removeAll(dataPath_); + fileutils::removeAll(cachePath_); + fileutils::removeAll(idPath_); +} + std::shared_ptr<SIPCall> RingAccount::newIncomingCall(const std::string& from) { @@ -1255,7 +1266,7 @@ RingAccount::loadValues() const } catch (const std::exception& e) { RING_ERR("Error reading value: %s", e.what()); } - remove(file.c_str()); + fileutils::remove(file); } RING_DBG("Loaded %zu values", values.size()); return values; diff --git a/src/ringdht/ringaccount.h b/src/ringdht/ringaccount.h index dc3e3b6a46c0eb567ab802d84e49f4f6f2334526..4c0e819169a3f6245fe6a3bcabd7a951f482d6b6 100644 --- a/src/ringdht/ringaccount.h +++ b/src/ringdht/ringaccount.h @@ -256,6 +256,9 @@ class RingAccount : public SIPAccountBase { void connectivityChanged() override; + public: // overloaded methods + void flush() override; + private: NON_COPYABLE(RingAccount); diff --git a/src/sip/sipaccountbase.cpp b/src/sip/sipaccountbase.cpp index 3fba632ccbc9c08baa557f883ba3bbbc898057d4..3b6dc65a60f30bdce9238fcf7782b70a3c659c2b 100644 --- a/src/sip/sipaccountbase.cpp +++ b/src/sip/sipaccountbase.cpp @@ -53,6 +53,15 @@ SIPAccountBase::SIPAccountBase(const std::string& accountID) SIPAccountBase::~SIPAccountBase() {} +void +SIPAccountBase::flush() +{ + // Class base method + Account::flush(); + + fileutils::remove(fileutils::get_cache_dir() + DIR_SEPARATOR_STR + getAccountID() + DIR_SEPARATOR_STR "messages"); +} + template <typename T> static void validate(std::string &member, const std::string ¶m, const T& valid) diff --git a/src/sip/sipaccountbase.h b/src/sip/sipaccountbase.h index 1f6db1466a8b442914a87681f7d1aae7c08121b7..0e45e7390f4742d1ae5df2a37b9b9e3090459edd 100644 --- a/src/sip/sipaccountbase.h +++ b/src/sip/sipaccountbase.h @@ -252,6 +252,9 @@ public: void connectivityChanged() override {}; +public: // overloaded methods + virtual void flush() override; + protected: virtual void serialize(YAML::Emitter &out) override; virtual void serializeTls(YAML::Emitter &out);