diff --git a/bin/dbus/cx.ring.Ring.PluginManagerInterface.xml b/bin/dbus/cx.ring.Ring.PluginManagerInterface.xml
index 5dd8e9d7f..cacbb47e8 100644
--- a/bin/dbus/cx.ring.Ring.PluginManagerInterface.xml
+++ b/bin/dbus/cx.ring.Ring.PluginManagerInterface.xml
@@ -154,5 +154,16 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bin/dbus/dbuspluginmanagerinterface.cpp b/bin/dbus/dbuspluginmanagerinterface.cpp
index 9bc0b098c..8b63ed470 100644
--- a/bin/dbus/dbuspluginmanagerinterface.cpp
+++ b/bin/dbus/dbuspluginmanagerinterface.cpp
@@ -132,3 +132,11 @@ DBusPluginManagerInterface::getCallMediaHandlerStatus()
{
return DRing::getCallMediaHandlerStatus();
}
+
+bool
+DBusPluginManagerInterface::addValueToPreference(const std::string& pluginId,
+ const std::string& preferenceKey,
+ const std::string& value)
+{
+ return DRing::addValueToPreference(pluginId, preferenceKey, value);
+}
diff --git a/bin/dbus/dbuspluginmanagerinterface.h b/bin/dbus/dbuspluginmanagerinterface.h
index 9fd353660..4ebaeb6db 100644
--- a/bin/dbus/dbuspluginmanagerinterface.h
+++ b/bin/dbus/dbuspluginmanagerinterface.h
@@ -71,4 +71,7 @@ class DRING_PUBLIC DBusPluginManagerInterface :
bool getPluginsEnabled();
void setPluginsEnabled(const bool& state);
std::map getCallMediaHandlerStatus();
+ bool addValueToPreference(const std::string& pluginId,
+ const std::string& preferenceKey,
+ const std::string& value);
};
diff --git a/bin/jni/plugin_manager_interface.i b/bin/jni/plugin_manager_interface.i
index 330c5c8dd..d995f67d8 100644
--- a/bin/jni/plugin_manager_interface.i
+++ b/bin/jni/plugin_manager_interface.i
@@ -42,4 +42,7 @@ std::map getCallMediaHandlerDetails(const std::string&
bool getPluginsEnabled();
void setPluginsEnabled(bool state);
std::map getCallMediaHandlerStatus();
+bool addValueToPreference(const std::string& pluginId,
+ const std::string& preferenceKey,
+ const std::string& value);
}
diff --git a/configure.ac b/configure.ac
index 2efeab897..65e785d1c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@ dnl Jami - configure.ac for automake 1.9 and autoconf 2.59
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ([2.65])
-AC_INIT([Jami Daemon],[9.5.0],[ring@gnu.org],[jami])
+AC_INIT([Jami Daemon],[9.6.0],[ring@gnu.org],[jami])
AC_COPYRIGHT([[Copyright (c) Savoir-faire Linux 2004-2020]])
AC_REVISION([$Revision$])
diff --git a/meson.build b/meson.build
index 9f49b57ba..86b0643e0 100644
--- a/meson.build
+++ b/meson.build
@@ -1,5 +1,5 @@
project('jami-daemon', ['c', 'cpp'],
- version: '9.5.0',
+ version: '9.6.0',
license: 'GPL3+',
default_options: ['cpp_std=gnu++17', 'buildtype=debugoptimized'],
meson_version:'>= 0.54'
diff --git a/src/client/plugin_manager_interface.cpp b/src/client/plugin_manager_interface.cpp
index 3e28ac6ca..97acea277 100644
--- a/src/client/plugin_manager_interface.cpp
+++ b/src/client/plugin_manager_interface.cpp
@@ -144,4 +144,14 @@ getCallMediaHandlerStatus()
.getCallServicesManager()
.getCallMediaHandlerStatus();
}
+
+bool
+addValueToPreference(const std::string& pluginId,
+ const std::string& preferenceKey,
+ const std::string& value)
+{
+ return jami::Manager::instance().getJamiPluginManager().addValueToPreference(pluginId,
+ preferenceKey,
+ value);
+}
} // namespace DRing
diff --git a/src/dring/plugin_manager_interface.h b/src/dring/plugin_manager_interface.h
index e99a5459f..01570212d 100644
--- a/src/dring/plugin_manager_interface.h
+++ b/src/dring/plugin_manager_interface.h
@@ -53,4 +53,7 @@ DRING_PUBLIC std::map getCallMediaHandlerDetails(const
DRING_PUBLIC bool getPluginsEnabled();
DRING_PUBLIC void setPluginsEnabled(bool state);
DRING_PUBLIC std::map getCallMediaHandlerStatus();
+DRING_PUBLIC bool addValueToPreference(const std::string& pluginId,
+ const std::string& preferenceKey,
+ const std::string& value);
}
diff --git a/src/fileutils.cpp b/src/fileutils.cpp
index 81e2290cf..b1576fba8 100644
--- a/src/fileutils.cpp
+++ b/src/fileutils.cpp
@@ -1023,5 +1023,35 @@ accessFile(const std::string& file, int mode)
#endif
}
+std::string
+getFileName(const std::string& filePath)
+{
+ std::string fileName = filePath;
+ const size_t last_slash_idx = fileName.find_last_of(DIR_SEPARATOR_STR_ESC);
+ if (std::string::npos != last_slash_idx) {
+ fileName.erase(0, last_slash_idx + 1);
+ }
+ return fileName;
+}
+
+std::string
+removeExtension(const std::string& filePath)
+{
+ std::string fileName = filePath;
+ const size_t period_idx = fileName.rfind('.');
+ if (std::string::npos != period_idx) {
+ fileName.erase(period_idx);
+ }
+ return fileName;
+}
+
+std::string
+getExtension(const std::string& filePath)
+{
+ std::string fileExt = filePath;
+ fileExt = fileExt.substr(fileExt.find_last_of('.'));
+ return fileExt;
+}
+
} // namespace jami
} // namespace fileutils
diff --git a/src/fileutils.h b/src/fileutils.h
index 57e424c31..9f1c54a52 100644
--- a/src/fileutils.h
+++ b/src/fileutils.h
@@ -176,6 +176,10 @@ std::string md5sum(const std::vector& buffer);
*/
int accessFile(const std::string& file, int mode);
+std::string getFileName(const std::string& filePath);
+std::string removeExtension(const std::string& filePath);
+std::string getExtension(const std::string& filePath);
+
} // namespace fileutils
} // namespace jami
diff --git a/src/plugin/jamipluginmanager.cpp b/src/plugin/jamipluginmanager.cpp
index 69d84e403..dd16401e5 100644
--- a/src/plugin/jamipluginmanager.cpp
+++ b/src/plugin/jamipluginmanager.cpp
@@ -34,6 +34,7 @@ extern "C" {
#include
}
+#include "fileutils.h"
#include
#include
@@ -337,11 +338,10 @@ JamiPluginManager::unloadPlugin(const std::string& rootPath)
void
JamiPluginManager::togglePlugin(const std::string& rootPath, bool toggle)
{
- //This function should not be used as is
- //One should modify it to perform plugin install followed by load
- //rootPath should be the jplpath!
- try
- {
+ // This function should not be used as is
+ // One should modify it to perform plugin install followed by load
+ // rootPath should be the jplpath!
+ try {
std::string soPath = getPluginDetails(rootPath).at("soPath");
// remove the previous plugin object if it was registered
pm_.destroyPluginComponents(soPath);
@@ -372,6 +372,8 @@ std::vector>
JamiPluginManager::getPluginPreferences(const std::string& rootPath)
{
const std::string preferenceFilePath = getPreferencesConfigFilePath(rootPath);
+ std::map> userPreferences
+ = getUserPreferencesValuesMap(rootPath);
std::ifstream file(preferenceFilePath);
Json::Value root;
Json::CharReaderBuilder rbuilder;
@@ -389,11 +391,34 @@ JamiPluginManager::getPluginPreferences(const std::string& rootPath)
std::string key = jsonPreference.get("key", "None").asString();
if (type != "None" && key != "None") {
if (keys.find(key) == keys.end()) {
- const auto& preferenceAttributes = parsePreferenceConfig(jsonPreference,
- type);
+ std::map preferenceAttributes
+ = parsePreferenceConfig(jsonPreference, type);
// If the parsing of the attributes was successful, commit the map and the key
if (!preferenceAttributes.empty()) {
- preferences.push_back(std::move(preferenceAttributes));
+ if (!userPreferences[key].empty()) {
+ preferenceAttributes["entryValues"]
+ = userPreferences[key]["entryValues"];
+ preferenceAttributes["entries"] = userPreferences[key]["entries"];
+ }
+
+ preferenceAttributes["entryValues"]
+ = std::regex_replace(preferenceAttributes["entryValues"],
+ std::regex("\\["),
+ "$2");
+ preferenceAttributes["entryValues"]
+ = std::regex_replace(preferenceAttributes["entryValues"],
+ std::regex("\\]"),
+ "$2");
+ preferenceAttributes["entries"]
+ = std::regex_replace(preferenceAttributes["entries"],
+ std::regex("\\["),
+ "$2");
+ preferenceAttributes["entries"]
+ = std::regex_replace(preferenceAttributes["entries"],
+ std::regex("\\]"),
+ "$2");
+
+ preferences.emplace_back(std::move(preferenceAttributes));
keys.insert(key);
}
}
@@ -443,6 +468,41 @@ JamiPluginManager::getPluginUserPreferencesValuesMap(const std::string& rootPath
return rmap;
}
+std::map>
+JamiPluginManager::getUserPreferencesValuesMap(const std::string& rootPath)
+{
+ const std::string preferencesValuesFilePath = pluginAddedPreferencesValuesFilePath(rootPath);
+ std::ifstream file(preferencesValuesFilePath, std::ios::binary);
+ std::map> rmap;
+
+ // If file is accessible
+ if (file.good()) {
+ std::lock_guard guard(fileutils::getFileLock(preferencesValuesFilePath));
+ // Get file size
+ std::string str;
+ file.seekg(0, std::ios::end);
+ size_t fileSize = static_cast(file.tellg());
+ // If not empty
+ if (fileSize > 0) {
+ // Read whole file content and put it in the string str
+ str.reserve(static_cast(file.tellg()));
+ file.seekg(0, std::ios::beg);
+ str.assign((std::istreambuf_iterator(file)), std::istreambuf_iterator());
+ file.close();
+ try {
+ // Unpack the string
+ msgpack::object_handle oh = msgpack::unpack(str.data(), str.size());
+ // Deserialized object is valid during the msgpack::object_handle instance is alive.
+ msgpack::object deserialized = oh.get();
+ deserialized.convert(rmap);
+ } catch (const std::exception& e) {
+ JAMI_ERR() << e.what();
+ }
+ }
+ }
+ return rmap;
+}
+
bool
JamiPluginManager::setPluginPreference(const std::string& rootPath,
const std::string& key,
@@ -521,6 +581,69 @@ JamiPluginManager::resetPluginPreferencesValuesMap(const std::string& rootPath)
return returnValue;
}
+bool
+JamiPluginManager::copyFileToPluginData(const std::string& pluginId,
+ const std::string& value,
+ const std::string& preferenceCategory,
+ std::string& fileName,
+ std::string& fileExt)
+{
+ if (!fileutils::isFile(value))
+ return false;
+
+ const std::string destinationDir {pluginId + DIR_SEPARATOR_CH + "data" + DIR_SEPARATOR_CH
+ + preferenceCategory + DIR_SEPARATOR_CH};
+ fileName = fileutils::removeExtension(fileutils::getFileName(value));
+ fileExt = fileutils::getExtension(value);
+
+ auto srcData = fileutils::loadFile(value);
+
+ if (fileutils::isFile(destinationDir + fileName + fileExt)) {
+ fileutils::saveFile(destinationDir + fileName + fileExt, srcData);
+ return false;
+ }
+ fileutils::saveFile(destinationDir + fileName + fileExt, srcData);
+ return true;
+}
+
+bool
+JamiPluginManager::addValueToPreference(const std::string& pluginId,
+ const std::string& preferenceKey,
+ const std::string& value)
+{
+ std::map> userPreferences
+ = getUserPreferencesValuesMap(pluginId);
+ std::vector> preferences = getPluginPreferences(pluginId);
+
+ for (auto& preference : preferences) {
+ if (preference["key"] == preferenceKey) {
+ std::string fileName, fileExt;
+ if (!copyFileToPluginData(pluginId, value, preference["category"], fileName, fileExt)) {
+ return setPluginPreference(pluginId, preferenceKey, fileName + fileExt);
+ }
+ setPluginPreference(pluginId, preferenceKey, fileName + fileExt);
+ userPreferences[preferenceKey]["entries"] = preference["entries"] + "," + fileName;
+ userPreferences[preferenceKey]["entryValues"] = preference["entryValues"] + ","
+ + fileName + fileExt;
+
+ const std::string preferencesValuesFilePath = pluginAddedPreferencesValuesFilePath(
+ pluginId);
+ std::ofstream fs(preferencesValuesFilePath, std::ios::binary);
+ if (!fs.good()) {
+ return false;
+ }
+ try {
+ std::lock_guard guard(fileutils::getFileLock(preferencesValuesFilePath));
+ msgpack::pack(fs, userPreferences);
+ return true;
+ } catch (const std::exception& e) {
+ JAMI_ERR() << e.what();
+ return false;
+ }
+ }
+ }
+}
+
std::map
JamiPluginManager::readPluginManifestFromArchive(const std::string& jplPath)
{
diff --git a/src/plugin/jamipluginmanager.h b/src/plugin/jamipluginmanager.h
index fb37398d3..d3c9ad158 100644
--- a/src/plugin/jamipluginmanager.h
+++ b/src/plugin/jamipluginmanager.h
@@ -125,6 +125,10 @@ public:
bool resetPluginPreferencesValuesMap(const std::string& rootPath);
+ bool addValueToPreference(const std::string& pluginId,
+ const std::string& preferenceKey,
+ const std::string& value);
+
public:
CallServicesManager& getCallServicesManager() { return csm_; }
@@ -180,6 +184,13 @@ private:
}
std::map getPluginUserPreferencesValuesMap(const std::string& rootPath);
+ std::map> getUserPreferencesValuesMap(
+ const std::string& rootPath);
+ bool copyFileToPluginData(const std::string& pluginId,
+ const std::string& value,
+ const std::string& preferenceCategory,
+ std::string& fileName,
+ std::string& fileExt);
/**
* @brief getPreferencesConfigFilePath
@@ -205,6 +216,18 @@ private:
return rootPath + DIR_SEPARATOR_CH + "preferences.msgpack";
}
+ /**
+ * @brief pluginAddedPreferencesValuesFilePath
+ * Returns the plugin added preferences values file path from the plugin root path
+ * This is entirely defined by how the plugin files are structured
+ * @param plugin rootPath
+ * @return path of the preferences values
+ */
+ std::string pluginAddedPreferencesValuesFilePath(const std::string& rootPath) const
+ {
+ return rootPath + DIR_SEPARATOR_CH + "addedPreferences.msgpack";
+ }
+
void registerServices();
private:
diff --git a/src/plugin/mediahandler.h b/src/plugin/mediahandler.h
index 422a79913..7a25457da 100644
--- a/src/plugin/mediahandler.h
+++ b/src/plugin/mediahandler.h
@@ -40,8 +40,8 @@ public:
* The id is the path of the plugin that created this MediaHandler
* @return
*/
- std::string id() const { return id_;}
- virtual void setId(const std::string& id) final {id_ = id;}
+ std::string id() const { return id_; }
+ virtual void setId(const std::string& id) final { id_ = id; }
private:
std::string id_;