From 95e19aa0cee4bcd79016182f94bc604b965409f8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micka=C3=ABl=20Turnel?=
 <mickael.turnel@belledonne-communications.com>
Date: Thu, 22 Jun 2023 11:15:53 +0200
Subject: [PATCH] Make the tester usable without installing

---
 config.h.cmake                   |  9 +++++++++
 include/linphone/api/c-factory.h | 20 ++++++++++++++++++--
 plugins/example/CMakeLists.txt   |  2 ++
 src/c-wrapper/api/c-factory.cpp  | 22 +++++++++++++++-------
 src/core/core.cpp                | 12 ++++++++----
 src/factory/factory.cpp          |  8 ++++++++
 src/factory/factory.h            |  4 ++++
 tester/liblinphone_tester.c      | 15 +++++++++++++++
 tester/liblinphone_tester.h      |  3 +++
 tester/tester.cpp                | 16 +++++++++++++++-
 10 files changed, 97 insertions(+), 14 deletions(-)

diff --git a/config.h.cmake b/config.h.cmake
index 3323b09113..6bf170bc7f 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -42,6 +42,15 @@
 #define PACKAGE_SOUND_DIR "${PACKAGE_SOUND_DIR}"
 #define PACKAGE_RING_DIR "${PACKAGE_RING_DIR}"
 
+#define LIBLINPHONE_LOCAL_RESOURCE_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/tester"
+
+#define VCARD_LOCAL_GRAMMAR_LOCATION "${CMAKE_SOURCE_DIR}/belcard/src"
+#define SDP_LOCAL_GRAMMAR_LOCATION "${CMAKE_SOURCE_DIR}/belle-sip/src/sdp"
+#define LIBLINPHONE_LOCAL_GRAMMARS_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/share"
+
+#define MEDIASTREAMER2_LOCAL_PLUGINS_LOCATION "${CMAKE_BINARY_DIR}/lib/mediastreamer2/plugins"
+#define LIBLINPHONE_LOCAL_PLUGINS_LOCATION "${CMAKE_BINARY_DIR}/lib/liblinphone/plugins"
+
 #cmakedefine BUILD_WIZARD
 #cmakedefine HAVE_NOTIFY4
 #cmakedefine HAVE_ZLIB 1
diff --git a/include/linphone/api/c-factory.h b/include/linphone/api/c-factory.h
index b7d84c9367..af0268fc16 100644
--- a/include/linphone/api/c-factory.h
+++ b/include/linphone/api/c-factory.h
@@ -253,8 +253,9 @@ LINPHONE_PUBLIC LinphoneAuthInfo *linphone_factory_create_auth_info_2(const Linp
  * @param realm the real to use. @notnil
  * @param algorithm the algorithm to use (MD5 or SHA-256). @notnil
  * @return the generated hash if it succeeded, NULL otherwise. @maybenil @tobefreed
-*/
-LINPHONE_PUBLIC char * linphone_factory_compute_ha1_for_algorithm(const LinphoneFactory *factory, const char *userid, const char *password, const char *realm, const char *algorithm);
+ */
+LINPHONE_PUBLIC char *linphone_factory_compute_ha1_for_algorithm(
+    const LinphoneFactory *factory, const char *userid, const char *password, const char *realm, const char *algorithm);
 
 /**
  * Create a #LinphoneCallCbs object that holds callbacks for events happening on a call.
@@ -428,6 +429,21 @@ LINPHONE_PUBLIC const char *linphone_factory_get_msplugins_dir(LinphoneFactory *
  */
 LINPHONE_PUBLIC void linphone_factory_set_msplugins_dir(LinphoneFactory *factory, const char *path);
 
+/**
+ * Get the directory where the liblinphone plugins are located.
+ * @param factory #LinphoneFactory object @notnil
+ * @return The path to the directory where the liblinphone plugins are located, or NULL if it has not been set.
+ * @maybenil
+ */
+LINPHONE_PUBLIC const char *linphone_factory_get_liblinphone_plugins_dir(LinphoneFactory *factory);
+
+/**
+ * Set the directory where the liblinphone plugins are located.
+ * @param factory #LinphoneFactory object @notnil
+ * @param path The path to the directory where the liblinphone plugins are located @maybenil
+ */
+LINPHONE_PUBLIC void linphone_factory_set_liblinphone_plugins_dir(LinphoneFactory *factory, const char *path);
+
 /**
  * Get the config path
  * @param factory the #LinphoneFactory @notnil
diff --git a/plugins/example/CMakeLists.txt b/plugins/example/CMakeLists.txt
index ff12e0c15a..c69704299e 100644
--- a/plugins/example/CMakeLists.txt
+++ b/plugins/example/CMakeLists.txt
@@ -24,6 +24,8 @@
 cmake_minimum_required(VERSION 3.22)
 project(exampleplugin VERSION 1.1.1 LANGUAGES C CXX)
 
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/liblinphone/plugins")
+
 set(PACKAGE "${PROJECT_NAME}")
 set(PACKAGE_NAME "${PROJECT_NAME}")
 set(PACKAGE_VERSION "${PROJECT_VERSION}")
diff --git a/src/c-wrapper/api/c-factory.cpp b/src/c-wrapper/api/c-factory.cpp
index 47b1bdd885..19561f730a 100644
--- a/src/c-wrapper/api/c-factory.cpp
+++ b/src/c-wrapper/api/c-factory.cpp
@@ -139,13 +139,13 @@ LinphoneAuthInfo *linphone_factory_create_auth_info_2(const LinphoneFactory *fac
 	                                               algorithm ? algorithm : "");
 }
 
-char * linphone_factory_compute_ha1_for_algorithm(const LinphoneFactory *factory, const char *userid, const char *password, const char *realm, const char *algorithm) {
-	auto ha1 = Factory::toCpp(factory)->computeHa1ForAlgorithm(
-		userid ? userid : "",
-		password ? password : "",
-		realm ? realm : "",
-		algorithm ? algorithm : ""
-	);
+char *linphone_factory_compute_ha1_for_algorithm(const LinphoneFactory *factory,
+                                                 const char *userid,
+                                                 const char *password,
+                                                 const char *realm,
+                                                 const char *algorithm) {
+	auto ha1 = Factory::toCpp(factory)->computeHa1ForAlgorithm(userid ? userid : "", password ? password : "",
+	                                                           realm ? realm : "", algorithm ? algorithm : "");
 	if (ha1.empty()) {
 		return NULL;
 	} else {
@@ -263,6 +263,14 @@ void linphone_factory_set_msplugins_dir(LinphoneFactory *factory, const char *pa
 	Factory::toCpp(factory)->setMspluginsDir(path ? path : "");
 }
 
+const char *linphone_factory_get_liblinphone_plugins_dir(LinphoneFactory *factory) {
+	return Factory::nullifyEmptyString(Factory::toCpp(factory)->getLiblinphonePluginsDir());
+}
+
+void linphone_factory_set_liblinphone_plugins_dir(LinphoneFactory *factory, const char *path) {
+	Factory::toCpp(factory)->setLiblinphonePluginsDir(path ? path : "");
+}
+
 const char *linphone_factory_get_config_dir(LinphoneFactory *factory, void *context) {
 	return Factory::nullifyEmptyString(Factory::toCpp(factory)->getConfigDir(context));
 }
diff --git a/src/core/core.cpp b/src/core/core.cpp
index af6cd90f99..3bd0715f25 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -1798,16 +1798,20 @@ LinphoneAddress *Core::getAudioVideoConferenceFactoryAddress(const std::shared_p
 }
 
 void Core::initPlugins() {
-	std::string pluginDir;
+	std::string pluginDir = Factory::get()->getLiblinphonePluginsDir();
+
+	if (pluginDir.empty()) {
 #ifdef __APPLE__
-	pluginDir = getPlatformHelpers(getCCore())->getPluginsDir();
+		pluginDir = getPlatformHelpers(getCCore())->getPluginsDir();
 #else
 #ifdef LINPHONE_PACKAGE_PLUGINS_DIR
-	pluginDir = LINPHONE_PACKAGE_PLUGINS_DIR;
+		pluginDir = LINPHONE_PACKAGE_PLUGINS_DIR;
 #else
-	pluginDir = "";
+		pluginDir = "";
 #endif
 #endif
+	}
+
 	if (!pluginDir.empty()) {
 		lInfo() << "Loading linphone core plugins from " << pluginDir;
 		loadPlugins(pluginDir);
diff --git a/src/factory/factory.cpp b/src/factory/factory.cpp
index c3b5d998ad..14155aa561 100644
--- a/src/factory/factory.cpp
+++ b/src/factory/factory.cpp
@@ -480,6 +480,14 @@ void Factory::setMspluginsDir(const std::string &path) {
 	mMspluginsDir = path;
 }
 
+const std::string &Factory::getLiblinphonePluginsDir() const {
+	return mLiblinphonePluginsDir;
+}
+
+void Factory::setLiblinphonePluginsDir(const std::string &path) {
+	mLiblinphonePluginsDir = path;
+}
+
 const std::string &Factory::getConfigDir(void *context) {
 	if (!mConfigDir.empty()) return mConfigDir;
 	mCachedConfigDir = LinphonePrivate::Paths::getPath(LinphonePrivate::Paths::Config, context);
diff --git a/src/factory/factory.h b/src/factory/factory.h
index 73614695a1..95314db407 100644
--- a/src/factory/factory.h
+++ b/src/factory/factory.h
@@ -152,6 +152,9 @@ public:
 	const std::string &getMspluginsDir() const;
 	void setMspluginsDir(const std::string &path);
 
+	const std::string &getLiblinphonePluginsDir() const;
+	void setLiblinphonePluginsDir(const std::string &path);
+
 	LinphoneErrorInfo *createErrorInfo() const;
 	LinphoneRange *createRange() const;
 	LinphoneTransports *createTransports() const;
@@ -248,6 +251,7 @@ private:
 	std::string mRingResourcesDir;
 	std::string mImageResourcesDir;
 	std::string mMspluginsDir;
+	std::string mLiblinphonePluginsDir;
 	std::string mConfigDir;
 	std::string mDataDir;
 	std::string mDownloadDir;
diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c
index ea531e7a9e..f400281c66 100644
--- a/tester/liblinphone_tester.c
+++ b/tester/liblinphone_tester.c
@@ -120,6 +120,21 @@ static int liblinphone_tester_start(int argc, char *argv[]) {
 	liblinphone_tester_init(NULL);
 	linphone_core_set_log_level(ORTP_ERROR);
 
+#ifdef HAVE_CONFIG_H
+	// If the tester is not installed we configure it, so it can be launched without installing
+	if (!liblinphone_tester_is_executable_installed(argv[0], "rcfiles/marie_rc")) {
+		bc_tester_set_resource_dir_prefix(LIBLINPHONE_LOCAL_RESOURCE_LOCATION);
+		printf("Resource dir set to %s\n", LIBLINPHONE_LOCAL_RESOURCE_LOCATION);
+
+		liblinphone_tester_add_grammar_loader_path(VCARD_LOCAL_GRAMMAR_LOCATION);
+		liblinphone_tester_add_grammar_loader_path(SDP_LOCAL_GRAMMAR_LOCATION);
+		liblinphone_tester_add_grammar_loader_path(LIBLINPHONE_LOCAL_GRAMMARS_LOCATION);
+
+		linphone_factory_set_msplugins_dir(linphone_factory_get(), MEDIASTREAMER2_LOCAL_PLUGINS_LOCATION);
+		linphone_factory_set_liblinphone_plugins_dir(linphone_factory_get(), LIBLINPHONE_LOCAL_PLUGINS_LOCATION);
+	}
+#endif
+
 	for (i = 1; i < argc; ++i) {
 		if (strcmp(argv[i], "--domain") == 0) {
 			CHECK_ARG("--domain", ++i, argc);
diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h
index 1a404c51e5..09ae54ac91 100644
--- a/tester/liblinphone_tester.h
+++ b/tester/liblinphone_tester.h
@@ -1013,6 +1013,9 @@ void liblinphone_tester_simulate_mire_defunct(
 bctbx_list_t *liblinphone_tester_resolve_name_to_ip_address(const char *name);
 bctbx_list_t *liblinphone_tester_remove_v6_addr(bctbx_list_t *l);
 
+bool_t liblinphone_tester_is_executable_installed(const char *executable, const char *resource);
+void liblinphone_tester_add_grammar_loader_path(const char *path);
+
 #ifdef __cplusplus
 };
 #endif
diff --git a/tester/tester.cpp b/tester/tester.cpp
index 7944a3816f..2df0ca3bff 100644
--- a/tester/tester.cpp
+++ b/tester/tester.cpp
@@ -18,12 +18,18 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <exception>
+#include <string>
+
+#include <bctoolbox/utils.hh>
+#include <belr/grammarbuilder.h>
+
 #ifdef HAVE_SOCI
 #include <soci/soci.h>
 #endif
+
 #include "liblinphone_tester.h"
 #include "logger/logger.h"
-#include <exception>
 
 /* */
 #ifndef _MSC_VER
@@ -70,3 +76,11 @@ uint64_t lime_get_userUpdateTs(const char *limedb) {
 #ifndef _MSC_VER
 #pragma GCC diagnostic pop
 #endif // _MSC_VER
+
+bool_t liblinphone_tester_is_executable_installed(const char *executable, const char *resource) {
+	return bctoolbox::Utils::isExecutableInstalled(std::string(executable), std::string(resource));
+}
+
+void liblinphone_tester_add_grammar_loader_path(const char *path) {
+	belr::GrammarLoader::get().addPath(std::string(path));
+}
-- 
GitLab