diff --git a/README b/README index fb5a8d8783632dd51e203c94d38c3c1cdaec4663..4c3f4383a9136e921ceae7ea0001b34758c85808 100644 --- a/README +++ b/README @@ -47,7 +47,7 @@ Short description of content of source tree - src/ is the core of DRing. - bin/ contains applications main code. - bin/dbus, the D-Bus xml interfaces, and c++ bindings - +- bin/restcpp, the C++ REST API implemented with Restbed About Savoir-faire Linux ------------------------ @@ -133,6 +133,27 @@ interaction between daemon and client will not work; for each platform where dbus is not available the client should implement all the methods in the *_stub.cpp files. +How to compile with the REST API +-------------------------------- + +Ring offers two REST API. One written in C++, and the other written in Cython. +Up to this date, only the C++ API is available. The Cython API will soon follow. + +To compile Ring-daemon with the C++ REST API, follow these two steps : + +1) Compile the dependencies +cd contrib +mkdir native +cd native +../bootstrap +make +make .restbed + +2) Then compile the daemon +cd ../../ +./autogen.sh +./configure --without-dbus --with-restcpp +make SIP accounts --------------------- diff --git a/bin/Makefile.am b/bin/Makefile.am index 92cfa4677b23e71de7151766a80be2a26d1ce2e4..deb5c45591be8e44eadf9c43d64a008f8ed62452 100644 --- a/bin/Makefile.am +++ b/bin/Makefile.am @@ -31,3 +31,19 @@ dring_CXXFLAGS= -I$(top_srcdir)/src ${DBUSCPP_CFLAGS} \ dring_LDADD = dbus/libclient_dbus.la ${DBUSCPP_LIBS} $(top_builddir)/src/libring.la endif + +if RING_RESTCPP +SUBDIRS=restcpp + +sbin_PROGRAMS = dring + +dring_SOURCES = main.cpp + +dring_CXXFLAGS= -g \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/dring \ + -DREST_API \ + -DTOP_BUILDDIR=\"$$(cd "$(top_builddir)"; pwd)\" + +dring_LDADD = restcpp/libclient_rest.la $(top_builddir)/src/libring.la +endif diff --git a/bin/main.cpp b/bin/main.cpp index 3f24024f228a12a1858d36418089ba8179ac136f..2590424a6f0b067d31080ef94e1dbf642cad37e6 100644 --- a/bin/main.cpp +++ b/bin/main.cpp @@ -4,6 +4,7 @@ * Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> * Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com> + * Author: Simon Zeni <simon.zeni@savoirfairelinux.com> * * 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 @@ -25,12 +26,28 @@ #include <cstring> #include <signal.h> #include <getopt.h> +#include <cstdlib> +#include "dring/dring.h" + +#include "logger.h" + +#if REST_API +#include "restcpp/restclient.h" +#else #include "dbus/dbusclient.h" +#endif + #include "fileutils.h" static int ringFlags = 0; -static std::unique_ptr<DBusClient> dbusClient; +static int port = 8080; + +#if REST_API + static std::unique_ptr<RestClient> restClient; +#else + static std::unique_ptr<DBusClient> dbusClient; +#endif static void print_title() @@ -52,6 +69,7 @@ print_usage() "-c, --console \t- Log in console (instead of syslog)" << std::endl << "-d, --debug \t- Debug mode (more verbose)" << std::endl << "-p, --persistent \t- Stay alive after client quits" << std::endl << + "--port \t- Port to use for the rest API. Default is 8080" << std::endl << "--auto-answer \t- Force automatic answer to incoming calls" << std::endl << "-h, --help \t- Print help" << std::endl; } @@ -76,6 +94,7 @@ parse_args(int argc, char *argv[], bool& persistent) {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'v'}, {"auto-answer", no_argument, &autoAnswer, true}, + {"port", optional_argument, NULL, 'x'}, {0, 0, 0, 0} /* Sentinel */ }; @@ -83,7 +102,7 @@ parse_args(int argc, char *argv[], bool& persistent) /* getopt_long stores the option index here. */ int option_index = 0; - auto c = getopt_long(argc, argv, "dcphv", long_options, &option_index); + auto c = getopt_long(argc, argv, "dcphvx:", long_options, &option_index); // end of the options if (c == -1) @@ -111,6 +130,10 @@ parse_args(int argc, char *argv[], bool& persistent) versionFlag = true; break; + case 'x': + port = std::atoi(optarg); + break; + default: break; } @@ -138,21 +161,6 @@ parse_args(int argc, char *argv[], bool& persistent) return false; } -static int -run() -{ - if (dbusClient) - return dbusClient->event_loop(); - return 1; -} - -static void -interrupt() -{ - if (dbusClient) - dbusClient->exit(); -} - static void signal_handler(int code) { @@ -164,7 +172,14 @@ signal_handler(int code) signal(SIGINT, SIG_DFL); signal(SIGTERM, SIG_DFL); - interrupt(); + // Interrupt the process +#if REST_API + if (restClient) + restClient->exit(); +#else + if (dbusClient) + dbusClient->exit(); +#endif } int @@ -189,6 +204,25 @@ main(int argc, char *argv []) if (parse_args(argc, argv, persistent)) return 0; + // TODO: Block signals for all threads but the main thread, decide how/if we should + // handle other signals + signal(SIGINT, signal_handler); + signal(SIGHUP, signal_handler); + signal(SIGTERM, signal_handler); + +#if REST_API + try { + restClient.reset(new RestClient {port, ringFlags, persistent}); + } catch (const std::exception& ex) { + std::cerr << "One does not simply initialize the rest client: " << ex.what() << std::endl; + return 1; + } + + if (restClient) + return restClient->event_loop(); + else + return 1; +#else // initialize client/library try { dbusClient.reset(new DBusClient {ringFlags, persistent}); @@ -197,11 +231,10 @@ main(int argc, char *argv []) return 1; } - // TODO: Block signals for all threads but the main thread, decide how/if we should - // handle other signals - signal(SIGINT, signal_handler); - signal(SIGHUP, signal_handler); - signal(SIGTERM, signal_handler); + if (dbusClient) + return dbusClient->event_loop(); + else + return 1; +#endif - return run(); } diff --git a/bin/restcpp/Makefile.am b/bin/restcpp/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..2f5e1e5c2e5e5ab500880565b2b2cce19e382973 --- /dev/null +++ b/bin/restcpp/Makefile.am @@ -0,0 +1,26 @@ +include $(top_srcdir)/globals.mak + +noinst_LTLIBRARIES = libclient_rest.la + +libclient_rest_la_SOURCES = \ + restclient.cpp \ + restclient.h \ + restconfigurationmanager.cpp \ + restconfigurationmanager.h \ + restvideomanager.cpp \ + restvideomanager.h + +libclient_rest_la_CXXFLAGS = \ + -std=c++14 \ + -g \ + -Wall \ + -Wextra \ + -Wno-reorder \ + -Wno-unused-variable \ + -Wno-unused-parameter \ + -pedantic \ + -I$(top_srcdir)/src + +libclient_rest_la_LDFLAGS = \ + -lpthread \ + -lrestbed diff --git a/bin/restcpp/restclient.cpp b/bin/restcpp/restclient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8e252dd657b32b1144aad42bf279aca7b761c240 --- /dev/null +++ b/bin/restcpp/restclient.cpp @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2016 Savoir-faire Linux Inc. + * + * Author: Simon Zeni <simon.zeni@savoirfairelinux.com> + * + * 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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include "restclient.h" + +RestClient::RestClient(int port, int flags, bool persistent) : + service_() +{ + configurationManager_.reset(new RestConfigurationManager()); + videoManager_.reset(new RestVideoManager()); + + if (initLib(flags) < 0) + throw std::runtime_error {"cannot initialize libring"}; + + // Fill the resources + initResources(); + + // Initiate the rest service + settings_ = std::make_shared<restbed::Settings>(); + settings_->set_port(port); + settings_->set_default_header( "Connection", "close" ); + RING_INFO("Restclient running on port [%d]", port); + + // Make it run in a thread, because this is a blocking function + restbed = std::thread([this](){ + service_.start(settings_); + }); +} + +RestClient::~RestClient() +{ + RING_INFO("destroying RestClient"); + exit(); +} + +int +RestClient::event_loop() noexcept +{ + // While the client is running, the events are polled every 10 milliseconds + RING_INFO("Restclient starting to poll events"); + while(!pollNoMore_) + { + DRing::pollEvents(); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + return 0; +} + +int +RestClient::exit() noexcept +{ + try { + // On exit, the client stop polling events + pollNoMore_ = true; + // The rest service is stopped + service_.stop(); + // And the thread running the service is joined + restbed.join(); + endLib(); + } catch (const std::exception& err) { + std::cerr << "quitting: " << err.what() << std::endl; + return 1; + } + + return 0; +} + +int +RestClient::initLib(int flags) +{ + using namespace std::placeholders; + + using std::bind; + using DRing::exportable_callback; + using DRing::CallSignal; + using DRing::ConfigurationSignal; + using DRing::PresenceSignal; + using DRing::AudioSignal; + + using SharedCallback = std::shared_ptr<DRing::CallbackWrapperBase>; + + auto confM = configurationManager_.get(); + +#ifdef RING_VIDEO + using DRing::VideoSignal; +#endif + + // Configuration event handlers + + // This is a short example of a callbakc using a lambda. In this case, this displays the incomming messages + const std::map<std::string, SharedCallback> configEvHandlers = { + exportable_callback<ConfigurationSignal::IncomingAccountMessage>([] + (const std::string& accountID, const std::string& from, const std::map<std::string, std::string>& payloads){ + RING_INFO("accountID : %s", accountID.c_str()); + RING_INFO("from : %s", from.c_str()); + RING_INFO("payloads"); + for(auto& it : payloads) + RING_INFO("%s : %s", it.first.c_str(), it.second.c_str()); + + }), + }; + + if (!DRing::init(static_cast<DRing::InitFlag>(flags))) + return -1; + + registerConfHandlers(configEvHandlers); + + // Dummy callbacks are registered for the other managers + registerCallHandlers(std::map<std::string, std::shared_ptr<DRing::CallbackWrapperBase>>()); + registerPresHandlers(std::map<std::string, std::shared_ptr<DRing::CallbackWrapperBase>>()); +#ifdef RING_VIDEO + registerVideoHandlers(std::map<std::string, std::shared_ptr<DRing::CallbackWrapperBase>>()); +#endif + + if (!DRing::start()) + return -1; + + return 0; +} + +void +RestClient::endLib() noexcept +{ + DRing::fini(); +} + +void +RestClient::initResources() +{ + // This is the function that initiates the resources. + // Each resources is defined by a route and a void function with a shared pointer to the session as argument + + // In this case, here's an example of the default route. It will list all the managers availables + auto default_res = std::make_shared<restbed::Resource>(); + default_res->set_path("/"); + default_res->set_method_handler("GET", [](const std::shared_ptr<restbed::Session> session){ + + RING_INFO("[%s] GET /", session->get_origin().c_str()); + + std::string body = "Available routes are : \r\n/configurationManager\r\n/videoManager\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + }); + + // And finally, we give the resource to the service to handle it + service_.publish(default_res); + + // For the sake of convenience, each manager sends a vector of their resources + for(auto& it : configurationManager_->getResources()) + service_.publish(it); + + for(auto& it : videoManager_->getResources()) + service_.publish(it); +} diff --git a/bin/restcpp/restclient.h b/bin/restcpp/restclient.h new file mode 100644 index 0000000000000000000000000000000000000000..382392a3d331225e6d96226f53e60042f28c1404 --- /dev/null +++ b/bin/restcpp/restclient.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2016 Savoir-faire Linux Inc. + * + * Author: Simon Zeni <simon.zeni@savoirfairelinux.com> + * + * 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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#pragma once + +#include <memory> +#include <chrono> +#include <map> +#include <vector> +#include <string> +#include <iostream> +#include <thread> + +#include <functional> +#include <iterator> +#include <restbed> + +#include "dring/dring.h" +#include "dring/callmanager_interface.h" +#include "dring/configurationmanager_interface.h" +#include "dring/presencemanager_interface.h" +#ifdef RING_VIDEO +#include "dring/videomanager_interface.h" +#endif +#include "logger.h" +#include "restconfigurationmanager.h" +#include "restvideomanager.h" + +class RestClient { + public: + RestClient(int port, int flags, bool persistent); + ~RestClient(); + + int event_loop() noexcept; + int exit() noexcept; + + private: + int initLib(int flags); + void endLib() noexcept; + void initResources(); + + bool pollNoMore_ = false; + + std::unique_ptr<RestConfigurationManager> configurationManager_; + std::unique_ptr<RestVideoManager> videoManager_; + + // Restbed attributes + restbed::Service service_; + std::shared_ptr<restbed::Settings> settings_; + std::thread restbed; +}; diff --git a/bin/restcpp/restconfigurationmanager.cpp b/bin/restcpp/restconfigurationmanager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8550e500fef78693005bf99f8b7bfb4ef100ad1b --- /dev/null +++ b/bin/restcpp/restconfigurationmanager.cpp @@ -0,0 +1,1811 @@ +/* + * Copyright (C) 2016 Savoir-faire Linux Inc. + * + * Author: Simon Zeni <simon.zeni@savoirfairelinux.com> + * + * 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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include "restconfigurationmanager.h" + +RestConfigurationManager::RestConfigurationManager() : + resources_() +{ + // We start by filling the resources_ array with all the resources + populateResources(); +} + +std::vector<std::shared_ptr<restbed::Resource>> +RestConfigurationManager::getResources() +{ + return resources_; +} + +// Private + +std::map<std::string, std::string> +RestConfigurationManager::parsePost(const std::string& post) +{ + // Simple function to parse a POST request like "param1=value1¶m2=value2" + std::map<std::string, std::string> data; + + auto split = [](const std::string& s, char delim){ + std::vector<std::string> v; + auto i = 0; + auto pos = s.find(delim); + while (pos != std::string::npos) + { + v.push_back(s.substr(i, pos-i)); + i = ++pos; + pos = s.find(delim, pos); + + if (pos == std::string::npos) + v.push_back(s.substr(i, s.length())); + } + + return v; + }; + + if(post.find_first_of('&') != std::string::npos) + { + std::vector<std::string> v = split(post, '&'); + + for(auto& it : v) + { + std::vector<std::string> tmp = split(it, '='); + data[tmp.front()] = tmp.back(); + } + } + else + { + std::vector<std::string> tmp = split(post, '='); + data[tmp.front()] = tmp.back(); + } + + return data; +} + +void +RestConfigurationManager::populateResources() +{ + // This function is atrociously long and redundant, but it works. Sorry + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/configurationManager"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::defaultRoute, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/accountDetails/{accountID: [a-z0-9]*}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getAccountDetails, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/volatileAccountDetails/{accountID: [a-z0-9]*}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getVolatileAccountDetails, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/setAccountDetails/{accountID: [a-z0-9]*}"); + resources_.back()->set_method_handler("POST", + std::bind(&RestConfigurationManager::setAccountDetails, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/setAccountActive/{accountID: [a-z0-9]*}/{status: (true|false)}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::setAccountActive, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/accountTemplate/{type: [a-zA-Z]*}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getAccountTemplate, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/addAccount"); + resources_.back()->set_method_handler("POST", + std::bind(&RestConfigurationManager::addAccount, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/removeAccount/{accountID: [a-z0-9]*}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::removeAccount, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/accountList"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getAccountList, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/sendRegister/{accountID: [a-z0-9]*}/{status: (true|false)}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::sendRegister, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/registerAllAccounts"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::registerAllAccounts, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/sendTextMessage/{accountID: [a-z0-9]*}/{to: [a-z0-9]*}"); + resources_.back()->set_method_handler("POST", + std::bind(&RestConfigurationManager::sendTextMessage, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/messageStatus/{id: [0-9]*}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getMessageStatus, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/tlsDefaultSettings"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getTlsDefaultSettings, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/codecList"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getCodecList, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/supportedTlsMethod"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getSupportedTlsMethod, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/supportedCiphers/{accountID: [a-z0-9]*}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getSupportedCiphers, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/codecDetails/{accountID: [a-z0-9]*}/{codecID: [0-9]*}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getCodecDetails, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/setCodecDetails/{accountID: [a-z0-9]*}/{codecID: [0-9]*}"); + resources_.back()->set_method_handler("POST", + std::bind(&RestConfigurationManager::getCodecDetails, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/activeCodecList/{accountID: [a-z0-9]*}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getActiveCodecList, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/audioPluginList"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getAudioPluginList, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/setAudioPlugin/{plugin: [a-zA-Z0-9]*}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::setAudioPlugin, this, std::placeholders::_1)); + /// + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/audioOutputDeviceList"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getAudioOutputDeviceList, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/setAudioOutputDevice/{index: [0-9]*}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::setAudioOutputDevice, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/setAudioInputDevice/{index: [0-9]*}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::setAudioInputDevice, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/setAudioRingtoneDevice/{plugin: [0-9]*}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::setAudioRingtoneDevice, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/audioInputDeviceList"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getAudioInputDeviceList, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/currentAudioDeviceIndex"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getCurrentAudioDevicesIndex, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/audioInputDeviceIndex/{name: [a-zA-Z0-9]*}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getAudioInputDeviceIndex, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/audioOutputDeviceIndex/{name: [a-zA-Z0-9]*}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getAudioInputDeviceIndex, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/currentAudioOutputPlugin"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getCurrentAudioOutputPlugin, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/noiseSuppressState"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getNoiseSuppressState, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/setNoiseSuppressState/{state: (true|false)"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::setNoiseSuppressState, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/isAgcEnable"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::isAgcEnabled, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/setAgcState/{state: (true|false)}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::setAgcState, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/muteDtmf/{state: (true|false)}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::muteDtmf, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/isDtmfMuted"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::isDtmfMuted, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/isCaptureMuted"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::isCaptureMuted, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/muteCapture/{state: (true|false)}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::muteCapture, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/isPlaybackMuted"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::isPlaybackMuted, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/mutePlayback/{state: (true|false)}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::mutePlayback, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/isRingtoneMuted"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::isRingtoneMuted, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/muteRingtone/{state: (true|false)}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::muteRingtone, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/audioManager"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getAudioManager, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/setAudioManager/{api: [a-zA-Z0-9]*}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::setAudioManager, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/supportedAudioManager"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getSupportedAudioManagers, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/recordPath"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getRecordPath, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/setRecordPath/{path: (\\/[a-zA-Z0-9\\.]{1,}){1,}([a-zA-Z0-9]*\\.[a-zA-Z]*)}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::setRecordPath, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/isAlwaysRecording"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getIsAlwaysRecording, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/setIsAlwaysRecording/{status: (true|false)}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::setIsAlwaysRecording, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/setHistoryLimit/{limit: [0-9]*}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::setHistoryLimit, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/getHistoryLimit"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getHistoryLimit, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/setAccountsOrder"); + resources_.back()->set_method_handler("POST", + std::bind(&RestConfigurationManager::setAccountsOrder, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/hookSettings"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getHookSettings, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/setHookSettings"); + resources_.back()->set_method_handler("POST", + std::bind(&RestConfigurationManager::setHookSettings, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/credentials/{accountID: [a-z0-9]*}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getCredentials, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/setCredentials/{accountID: [a-z0-9]*}"); + resources_.back()->set_method_handler("POST", + std::bind(&RestConfigurationManager::setCredentials, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/addrFromInterfaceName/{interface: [a-zA-Z0-9]}"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getAddrFromInterfaceName, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/allIpInterface"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getAllIpInterface, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/allIpInterfaceByName"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getAllIpInterfaceByName, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/shortcuts"); + resources_.back()->set_method_handler("GET", + std::bind(&RestConfigurationManager::getShortcuts, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/setShortcuts"); + resources_.back()->set_method_handler("POST", + std::bind(&RestConfigurationManager::setShortcuts, this, std::placeholders::_1)); +} + +void +RestConfigurationManager::defaultRoute(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /configurationManager", session->get_origin().c_str()); + + std::string body = "Available routes are : \r\n"; + body += "GET /accountDetails/{accountID: [a-z0-9]*}\r\n"; + body += "GET /volatileAccountDetails/{accountID: [a-z0-9]*}\r\n"; + body += "POST /setAccountDetails/{accountID: [a-z0-9]*}\r\n"; + body += "GET /setAccountActive/{accountID: [a-z0-9]*}/{status: (true|false)}\r\n"; + body += "GET /accountTemplate/{type: [a-zA-Z]*}\r\n"; + body += "POST /addAccount\r\n"; + body += "GET /removeAccount/{accountID: [a-z0-9]*}\r\n"; + body += "GET /accountList\r\n"; + body += "GET /sendRegister/{accountID: [a-z0-9]*}/{status: (true|false)}\r\n"; + body += "GET /registerAllAccounts\r\n"; + body += "POST /sendTextMessage/{accountID: [a-z0-9]*}/{to: [a-z0-9]*}\r\n"; + body += "GET /messageStatus/{id: [0-9]*}\r\n"; + body += "GET /tlsDefaultSettings\r\n"; + body += "GET /codecList\r\n"; + body += "GET /supportedTlsMethod\r\n"; + body += "GET /supportedCiphers/{accountID: [a-z0-9]*}\r\n"; + body += "GET /codecDetails/{accountID: [a-z0-9]*}/{codecID: [0-9]*}\r\n"; + body += "POST /setCodecDetails/{accountID: [a-z0-9]*}/{codecID: [0-9]*}\r\n"; + body += "GET /activeCodecList/{accountID: [a-z0-9]*}\r\n"; + body += "GET /audioPluginList\r\n"; + body += "GET /setAudioPlugin/{plugin: [a-zA-Z0-9]*}\r\n"; + body += "GET /audioOutputDeviceList\r\n"; + body += "GET /setAudioOutputDevice/{index: [0-9]*}\r\n"; + body += "GET /setAudioInputDevice/{index: [0-9]*}\r\n"; + body += "GET /setAudioRingtoneDevice/{index: [0-9]*}\r\n"; + body += "GET /audioInputDeviceList\r\n"; + body += "GET /currentAudioDeviceIndex\r\n"; + body += "GET /audioInputDeviceIndex/{name: [a-zA-Z0-9]*}\r\n"; + body += "GET /audioOutputDeviceIndex/{name: [a-zA-Z0-9]*}\r\n"; + body += "GET /currentAudioOutputPlugin\r\n"; + body += "GET /noiseSuppressState\r\n"; + body += "GET /setNoiseSuppressState/{state: (true|false)}\r\n"; + body += "GET /isAgcEnable\r\n"; + body += "GET /setAgcState/{state: (true|false)}\r\n"; + body += "GET /muteDtmf/{state: (true|false)}\r\n"; + body += "GET /isDtmfMuted\r\n"; + body += "GET /isCaptureMuted\r\n"; + body += "GET /muteCapture/{state: (true|false)}\r\n"; + body += "GET /isPlaybackMuted\r\n"; + body += "GET /mutePlayback/{state: (true|false)}\r\n"; + body += "GET /isRingtoneMuted\r\n"; + body += "GET /muteRingtone/{state: (true|false)}\r\n"; + body += "GET /audioManager\r\n"; + body += "GET /setAudioManager/{api: [a-zA-Z0-9]*}\r\n"; + body += "GET /supportedAudioManager\r\n"; + body += "GET /isIax2Enable\r\n"; + body += "GET /recordPath\r\n"; + body += "GET /setRecordPath/{path: (\\/[a-zA-Z0-9\\.]{1,}){1,}([a-zA-Z0-9]*\\.[a-zA-Z]*)}\r\n"; + body += "GET /isAlwaysRecording\r\n"; + body += "GET /setIsAlwaysRecording/{status: (true|false)}\r\n"; + body += "GET /setHistoryLimit/{limit: [0-9]*}\r\n"; + body += "GET /getHistoryLimit\r\n"; + body += "POST setAccountsOrder\r\n"; + body += "GET hookSettings\r\n"; + body += "POST setHookSettings\r\n"; + body += "GET credentials/{accountID: [a-z0-9]*}\r\n"; + body += "POST setCredentials/{accountID: [a-z0-9]*}\r\n"; + body += "GET addrFromInterfaceName/{interface: [a-zA-Z0-9]}\r\n"; + body += "GET allIpInterface\r\n"; + body += "GET allIpInterfaceByName\r\n"; + body += "GET shortcuts\r\n"; + body += "POST setShortcuts\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::getAccountDetails(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string accountID = request->get_path_parameter("accountID"); + + RING_INFO("[%s] GET /accountDetails/%s", session->get_origin().c_str(), accountID.c_str()); + + std::map<std::string, std::string> accountDetails = DRing::getAccountDetails(accountID); + + std::string body = ""; + + if(accountDetails.size() == 0) + { + session->close(restbed::NOT_FOUND); + } + else + { + for(auto it = std::begin(accountDetails); it != std::end(accountDetails); ++it) + body += it->first + " : " + it->second + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); + } +} + +void +RestConfigurationManager::getVolatileAccountDetails(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string accountID = request->get_path_parameter("accountID"); + + RING_INFO("[%s] GET /volatileAccountDetails/%s", session->get_origin().c_str(), accountID.c_str()); + + std::map<std::string, std::string> volatileAccountDetails = DRing::getAccountDetails(accountID); + + std::string body = ""; + + if(volatileAccountDetails.size() == 0) + { + session->close(restbed::NOT_FOUND); + } + else + { + for(auto it = std::begin(volatileAccountDetails); it != std::end(volatileAccountDetails); ++it) + body += it->first + " : " + it->second + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); + } +} + +void +RestConfigurationManager::setAccountDetails(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string accountID = request->get_path_parameter("accountID"); + size_t content_length = 0; + request->get_header("Content-Length", content_length); + + RING_INFO("[%s] POST /setAccountDetails/%s", session->get_origin().c_str(), accountID.c_str()); + + session->fetch(content_length, [this, request, accountID](const std::shared_ptr<restbed::Session> session, const restbed::Bytes & body) + { + std::string data(std::begin(body), std::end(body)); + + std::map<std::string, std::string> details = parsePost(data); + RING_DBG("Details received"); + for(auto& it : details) + RING_DBG("%s : %s", it.first.c_str(), it.second.c_str()); + + DRing::setAccountDetails(accountID, details); + + session->close(restbed::OK); + }); +} + +void +RestConfigurationManager::setAccountActive(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + auto path = request->get_path_parameters(); + + const std::string accountID = request->get_path_parameter("accountID"); + const bool active = (request->get_path_parameter("status") == "true" ? true : false); + + RING_INFO("[%s] GET /setAccountActive/%s/%s", session->get_origin().c_str(), accountID.c_str(), (active ? "true" : "false")); + + DRing::setAccountActive(accountID, active); + + session->close(restbed::OK); +} + +void +RestConfigurationManager::getAccountTemplate(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string accountType = request->get_path_parameter("type"); + + RING_INFO("[%s] GET /accountTemplate/%s", session->get_origin().c_str(), accountType.c_str()); + + std::map<std::string, std::string> accountTemplate = DRing::getAccountTemplate(accountType);; + + std::string body = ""; + + for(auto it = std::begin(accountTemplate); it != std::end(accountTemplate); ++it) + body += it->first + " : " + it->second + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::addAccount(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + size_t content_length = 0; + request->get_header("Content-Length", content_length); + + RING_INFO("[%s] POST /addAccount", session->get_origin().c_str()); + + session->fetch(content_length, [this, request](const std::shared_ptr<restbed::Session> session, const restbed::Bytes & body) + { + std::string data(std::begin(body), std::end(body)); + + std::map<std::string, std::string> details = parsePost(data); + RING_DBG("Details received"); + for(auto& it : details) + RING_DBG("%s : %s", it.first.c_str(), it.second.c_str()); + + DRing::addAccount(details); + + session->close(restbed::OK); + }); +} + +void +RestConfigurationManager::removeAccount(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string accountID = request->get_path_parameter("accountID"); + + RING_INFO("[%s] GET /removeAccount/%s", session->get_origin().c_str(), accountID.c_str()); + + DRing::removeAccount(accountID); + + // TODO : found a way to know if there's no accound with this id, and send a 404 NOT FOUND + // See account_factory.cpp:102 for the function + session->close(restbed::OK); +} + +void +RestConfigurationManager::getAccountList(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /accountList", session->get_origin().c_str()); + + std::vector<std::string> accountList = DRing::getAccountList(); + + std::string body = ""; + + for(auto& it : accountList) + { + body += "accountID : "; + body += it; + body += '\n'; + } + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::sendRegister(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + auto path = request->get_path_parameters(); + + const std::string accountID = request->get_path_parameter("accountID"); + const bool enable = (request->get_path_parameter("status") == "true" ? true : false); + + RING_INFO("[%s] GET /sendRegister/%s/%s", session->get_origin().c_str(), accountID.c_str(), (enable ? "true" : "false")); + + DRing::sendRegister(accountID, enable); + + session->close(restbed::OK); +} + +void +RestConfigurationManager::registerAllAccounts(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /registerAllAccounts", session->get_origin().c_str()); + + DRing::registerAllAccounts(); + + session->close(restbed::OK); +} + +void +RestConfigurationManager::sendTextMessage(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string accountID = request->get_path_parameter("accountID"); + const std::string to = request->get_path_parameter("to"); + + size_t content_length = 0; + request->get_header("Content-Length", content_length); + + RING_INFO("[%s] POST /sendTextMessage/%s/%s", session->get_origin().c_str(), accountID.c_str(), to.c_str()); + + session->fetch(content_length, [this, request, accountID, to](const std::shared_ptr<restbed::Session> session, const restbed::Bytes & body) + { + std::string data(std::begin(body), std::end(body)); + std::map<std::string, std::string> payloads = parsePost(data); + RING_DBG("Payloads received"); + for(auto& it : payloads) + RING_DBG("%s : %s", it.first.c_str(), it.second.c_str()); + + DRing::sendAccountTextMessage(accountID, to, payloads); + + session->close(restbed::OK); + }); +} + +void +RestConfigurationManager::getMessageStatus(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string id = request->get_path_parameter("id"); + + RING_INFO("[%s] GET /messageStatus/%s", session->get_origin().c_str(), id.c_str()); + + const std::uint64_t status = DRing::getMessageStatus(std::stoull(id)); + + std::string body = ""; + + if (status != static_cast<int>(ring::im::MessageStatus::UNKNOWN)) { + switch (status) { + case static_cast<int>(ring::im::MessageStatus::IDLE): + case static_cast<int>(ring::im::MessageStatus::SENDING): + body = "SENDING"; + break; + case static_cast<int>(ring::im::MessageStatus::SENT): + body = "SENT"; + break; + case static_cast<int>(ring::im::MessageStatus::READ): + body = "READ"; + break; + case static_cast<int>(ring::im::MessageStatus::FAILURE): + body = "FAILURE"; + break; + default: + body = "UNKNOWN"; + break; + } + } + else + { + body = "UNKNOWN"; + } + + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::getTlsDefaultSettings(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /tlsDefaultSettings", session->get_origin().c_str()); + + std::map<std::string, std::string> tlsDefault = DRing::getTlsDefaultSettings(); + + std::string body = ""; + + for(auto it = std::begin(tlsDefault); it != std::end(tlsDefault); ++it) + body += it->first + " : " + it->second + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::getCodecList(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /codecList", session->get_origin().c_str()); + + std::vector<unsigned> codec = DRing::getCodecList(); + + std::string body = ""; + + for(auto& it : codec) + body += std::to_string(it) + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::getSupportedTlsMethod(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /supportedTlsMethod", session->get_origin().c_str()); + + std::vector<std::string> supported = DRing::getSupportedTlsMethod(); + + std::string body = ""; + + for(auto& it : supported) + body += it + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::getSupportedCiphers(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string accountID = request->get_path_parameter("accountID"); + + RING_INFO("[%s] GET /supportedCiphers/%s", session->get_origin().c_str(), accountID.c_str()); + + std::vector<std::string> supported = DRing::getSupportedCiphers(accountID); + + std::string body = ""; + + for(auto& it : supported) + body += it + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::getCodecDetails(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string accountID = request->get_path_parameter("accountID"); + const std::string codecID = request->get_path_parameter("codecID"); + + RING_INFO("[%s] GET /codecDetails/%s/%s", session->get_origin().c_str(), accountID.c_str(), codecID.c_str()); + + std::map<std::string, std::string> details = DRing::getCodecDetails(accountID, std::stoi(codecID)); + + std::string body = ""; + + for(auto& it : details) + body += it.first + " : " + it.second + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::setCodecDetails(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string accountID = request->get_path_parameter("accountID"); + const std::string codecID = request->get_path_parameter("codecID"); + + size_t content_length = 0; + request->get_header("Content-Length", content_length); + + RING_INFO("[%s] POST /setCodecDetails/%s/%s", session->get_origin().c_str(), accountID.c_str(), codecID.c_str()); + + session->fetch(content_length, [this, request, accountID, codecID](const std::shared_ptr<restbed::Session> session, const restbed::Bytes & body) + { + std::string data(std::begin(body), std::end(body)); + std::map<std::string, std::string> details = parsePost(data); + + RING_DBG("Details received"); + for(auto& it : details) + RING_DBG("%s : %s", it.first.c_str(), it.second.c_str()); + + DRing::setCodecDetails(accountID, std::stoi(codecID), details); + + session->close(restbed::OK); + }); +} + +void +RestConfigurationManager::getActiveCodecList(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string accountID = request->get_path_parameter("accountID"); + + RING_INFO("[%s] GET /activeCodecList/%s", session->get_origin().c_str(), accountID.c_str()); + + std::vector<unsigned> codecs = DRing::getActiveCodecList(accountID); + + std::string body = ""; + + for(auto& it : codecs) + body += std::to_string(it) + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::setActiveCodecList(const std::string& accountID, const std::vector<unsigned>& list) +{ + // See restconfigurationmanager.h:70 + + //DRing::setActiveCodecList(accountID, list); +} + +void +RestConfigurationManager::getAudioPluginList(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /audioPluginList", session->get_origin().c_str()); + + std::vector<std::string> list = DRing::getAudioPluginList(); + + std::string body = ""; + + for(auto& it : list) + body += it + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::setAudioPlugin(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string plugin = request->get_path_parameter("plugin"); + + RING_INFO("[%s] GET /setAudioPlugin/%s", session->get_origin().c_str(), plugin.c_str()); + + DRing::setAudioPlugin(plugin); + + session->close(restbed::OK); +} + +void +RestConfigurationManager::getAudioOutputDeviceList(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /audioOutputDeviceList", session->get_origin().c_str()); + + std::vector<std::string> list = DRing::getAudioOutputDeviceList(); + + std::string body = ""; + + for(auto& it : list) + body += it + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::setAudioOutputDevice(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string index = request->get_path_parameter("index"); + + RING_INFO("[%s] GET /setAudioOutputDevice/%s", session->get_origin().c_str(), index.c_str()); + + DRing::setAudioOutputDevice(std::stoi(index)); + + session->close(restbed::OK); +} + +void +RestConfigurationManager::setAudioInputDevice(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string index = request->get_path_parameter("index"); + + RING_INFO("[%s] GET /setAudioInputDevice/%s", session->get_origin().c_str(), index.c_str()); + + DRing::setAudioInputDevice(std::stoi(index)); + + session->close(restbed::OK); +} + +void +RestConfigurationManager::setAudioRingtoneDevice(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string index = request->get_path_parameter("index"); + + RING_INFO("[%s] GET /setAudioRingtoneDevice/%s", session->get_origin().c_str(), index.c_str()); + + DRing::setAudioRingtoneDevice(std::stoi(index)); + + session->close(restbed::OK); +} + +void +RestConfigurationManager::getAudioInputDeviceList(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /audioInputDeviceList", session->get_origin().c_str()); + + std::vector<std::string> list = DRing::getAudioInputDeviceList(); + + std::string body = ""; + + for(auto& it : list) + body += it + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::getCurrentAudioDevicesIndex(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /currentAudioDevicesIndex", session->get_origin().c_str()); + + std::vector<std::string> list = DRing::getCurrentAudioDevicesIndex(); + + std::string body = ""; + + for(auto& it : list) + body += it + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::getAudioInputDeviceIndex(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string name = request->get_path_parameter("name"); + + RING_INFO("[%s] GET /audioInputDeviceIndex/%s", session->get_origin().c_str(), name.c_str()); + + std::int32_t index = DRing::getAudioInputDeviceIndex(name); + + std::string body = std::to_string(index) + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::getAudioOutputDeviceIndex(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string name = request->get_path_parameter("name"); + + RING_INFO("[%s] GET /audioOutputDeviceIndex/%s", session->get_origin().c_str(), name.c_str()); + + std::int32_t index = DRing::getAudioOutputDeviceIndex(name); + + std::string body = std::to_string(index) + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::getCurrentAudioOutputPlugin(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /currentAudioOutputPlugin", session->get_origin().c_str()); + + std::string body = DRing::getCurrentAudioOutputPlugin(); + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::getNoiseSuppressState(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /noiseSuppressState", session->get_origin().c_str()); + + std::string body = (DRing::getNoiseSuppressState() ? "true" : "false"); + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::setNoiseSuppressState(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string state = request->get_path_parameter("state"); + + RING_INFO("[%s] GET /setNoiseSuppressState/%s", session->get_origin().c_str(), state.c_str()); + + DRing::setNoiseSuppressState((state == "true" ? true : false)); + + session->close(restbed::OK); +} + +void +RestConfigurationManager::isAgcEnabled(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /isAgcEnable", session->get_origin().c_str()); + + bool status = DRing::isAgcEnabled(); + std::string body = (status ? "true" : "false"); + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::setAgcState(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string state = request->get_path_parameter("state"); + + RING_INFO("[%s] GET /setAgcState/%s", session->get_origin().c_str(), state.c_str()); + + DRing::setAgcState((state == "true" ? true : false)); + + session->close(restbed::OK); +} + +void +RestConfigurationManager::muteDtmf(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string state = request->get_path_parameter("state"); + + RING_INFO("[%s] GET /muteDtmf/%s", session->get_origin().c_str(), state.c_str()); + + DRing::muteDtmf((state == "true" ? true : false)); + + session->close(restbed::OK); +} + +void +RestConfigurationManager::isDtmfMuted(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /isDtmfMuted", session->get_origin().c_str()); + + bool status = DRing::isDtmfMuted(); + std::string body = (status ? "true" : "false"); + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::isCaptureMuted(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /isCaptureMuted", session->get_origin().c_str()); + + bool status = DRing::isCaptureMuted(); + std::string body = (status ? "true" : "false"); + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::muteCapture(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string state = request->get_path_parameter("state"); + + RING_INFO("[%s] GET /muteCapture/%s", session->get_origin().c_str(), state.c_str()); + + DRing::muteCapture((state == "true" ? true : false)); + + session->close(restbed::OK); +} + +void +RestConfigurationManager::isPlaybackMuted(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /isPlaybackMuted", session->get_origin().c_str()); + + bool status = DRing::isPlaybackMuted(); + std::string body = (status ? "true" : "false"); + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::mutePlayback(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string state = request->get_path_parameter("state"); + + RING_INFO("[%s] GET /mutePlayback/%s", session->get_origin().c_str(), state.c_str()); + + DRing::mutePlayback((state == "true" ? true : false)); + + session->close(restbed::OK); +} + +void +RestConfigurationManager::isRingtoneMuted(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /isRingtoneMuted", session->get_origin().c_str()); + + bool status = DRing::isRingtoneMuted(); + std::string body = (status ? "true" : "false"); + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::muteRingtone(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string state = request->get_path_parameter("state"); + + RING_INFO("[%s] GET /muteRingtone/%s", session->get_origin().c_str(), state.c_str()); + + DRing::muteRingtone((state == "true" ? true : false)); + + session->close(restbed::OK); +} + +void +RestConfigurationManager::getAudioManager(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /audioManager", session->get_origin().c_str()); + + std::string body = DRing::getAudioManager(); + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::setAudioManager(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string api = request->get_path_parameter("api"); + + RING_INFO("[%s] GET /setAudioManager/%s", session->get_origin().c_str(), api.c_str()); + + bool status = DRing::setAudioManager(api); + std::string body = (status ? "true" : "false"); + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::getSupportedAudioManagers(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + + RING_INFO("[%s] GET /supportedAudioManager", session->get_origin().c_str()); + + std::string body = ""; +#if HAVE_ALSA + body += ALSA_API_STR + "\r\n", +#endif +#if HAVE_PULSE + body += PULSEAUDIO_API_STR + "\r\n", +#endif +#if HAVE_JACK + body += JACK_API_STR + "\r\n", +#endif + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::getRecordPath(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /recordPath", session->get_origin().c_str()); + + std::string body = DRing::getRecordPath(); + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::setRecordPath(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string path = request->get_path_parameter("path"); + + RING_INFO("[%s] GET /setRecordPath/%s", session->get_origin().c_str(), path.c_str()); + + DRing::setRecordPath(path); + + session->close(restbed::OK); +} + +void +RestConfigurationManager::getIsAlwaysRecording(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /isAlwaysRecording", session->get_origin().c_str()); + + bool status = DRing::getIsAlwaysRecording(); + std::string body = (status ? "true" : "false"); + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::setIsAlwaysRecording(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string state = request->get_path_parameter("state"); + + RING_INFO("[%s] GET /setIsAlwaysRecording/%s", session->get_origin().c_str(), state.c_str()); + + DRing::setIsAlwaysRecording((state == "true" ? true : false)); + + session->close(restbed::OK); +} + +void +RestConfigurationManager::setHistoryLimit(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string days = request->get_path_parameter("limit"); + + RING_INFO("[%s] GET /setHistoryLimit/%s", session->get_origin().c_str(), days.c_str()); + + DRing::setHistoryLimit(std::stoi(days)); + + session->close(restbed::OK); +} + +void +RestConfigurationManager::getHistoryLimit(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /getHistoryLimit", session->get_origin().c_str()); + + std::string body = std::to_string(DRing::getHistoryLimit()); + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::setAccountsOrder(const std::shared_ptr<restbed::Session> session) +{ + // POST order=accountID/accountID/ (etc) + + const auto request = session->get_request(); + + size_t content_length = 0; + request->get_header("Content-Length", content_length); + + RING_INFO("[%s] POST /setAccountsOrder", session->get_origin().c_str()); + + session->fetch(content_length, [this](const std::shared_ptr<restbed::Session> session, const restbed::Bytes & body) + { + std::string data(std::begin(body), std::end(body)); + + std::map<std::string, std::string> details = parsePost(data); + RING_DBG("Order received"); + for(auto& it : details) + RING_DBG("%s : %s", it.first.c_str(), it.second.c_str()); + + std::regex order("[a-z0-9]{16}\\/"); + + auto search = details.find("order"); + if(search != details.end() && std::regex_match(details["order"], order)) + DRing::setAccountsOrder(details["order"]); + + session->close(restbed::OK); + }); +} + +void +RestConfigurationManager::getHookSettings(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /hookSettings", session->get_origin().c_str()); + + std::map<std::string, std::string> hooks = DRing::getHookSettings(); + + std::string body = ""; + + for(auto& it : hooks) + body += it.first + " : " + it.second + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::setHookSettings(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + + size_t content_length = 0; + request->get_header("Content-Length", content_length); + + RING_INFO("[%s] POST /setHookSettings", session->get_origin().c_str()); + + session->fetch(content_length, [this](const std::shared_ptr<restbed::Session> session, const restbed::Bytes & body) + { + std::string data(std::begin(body), std::end(body)); + + std::map<std::string, std::string> settings = parsePost(data); + RING_DBG("Settings received"); + for(auto& it : settings) + RING_DBG("%s : %s", it.first.c_str(), it.second.c_str()); + + DRing::setHookSettings(settings); + + session->close(restbed::OK); + }); +} + +void +RestConfigurationManager::getCredentials(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string accountID = request->get_path_parameter("accountID"); + + RING_INFO("[%s] GET /credentials/%s", session->get_origin().c_str(), accountID.c_str()); + + std::vector<std::map<std::string, std::string>> credentials = DRing::getCredentials(accountID); + + std::string body = ""; + + for(auto& it : credentials) + for(auto& i : it) + body += i.first + " : " + i.second + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::setCredentials(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string accountID = request->get_path_parameter("accountID"); + + RING_INFO("[%s] POST /setCredentials/%s", session->get_origin().c_str(), accountID.c_str()); + + size_t content_length = 0; + request->get_header("Content-Length", content_length); + + session->fetch(content_length, [this, accountID](const std::shared_ptr<restbed::Session> session, const restbed::Bytes & body) + { + std::string data(std::begin(body), std::end(body)); + + std::map<std::string, std::string> details = parsePost(data); + RING_DBG("Details received"); + for(auto& it : details) + RING_DBG("%s : %s", it.first.c_str(), it.second.c_str()); + + DRing::setCredentials(accountID, std::vector<std::map<std::string, std::string>>{details}); + + session->close(restbed::OK); + }); +} + +void +RestConfigurationManager::getAddrFromInterfaceName(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + const std::string interface = request->get_path_parameter("interface"); + + RING_INFO("[%s] GET /addrFromInterfaceName/%s", session->get_origin().c_str(), interface.c_str()); + + std::string body = DRing::getAddrFromInterfaceName(interface); + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::getAllIpInterface(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /allIpInterface", session->get_origin().c_str()); + + std::vector<std::string> interfaces = DRing::getAllIpInterface(); + + std::string body = ""; + + for(auto& it : interfaces) + body += it + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::getAllIpInterfaceByName(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /allIpInterfaceByName", session->get_origin().c_str()); + + std::vector<std::string> interfaces = DRing::getAllIpInterfaceByName(); + + std::string body = ""; + + for(auto& it : interfaces) + body += it + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::getShortcuts(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /shortcuts", session->get_origin().c_str()); + + std::map<std::string, std::string> shortcuts = DRing::getShortcuts(); + + std::string body = ""; + + for(auto& it : shortcuts) + body += it.first + " : " + it.second + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void +RestConfigurationManager::setShortcuts(const std::shared_ptr<restbed::Session> session) +{ + const auto request = session->get_request(); + + RING_INFO("[%s] POST /setShortcuts", session->get_origin().c_str()); + + size_t content_length = 0; + request->get_header("Content-Length", content_length); + + session->fetch(content_length, [this](const std::shared_ptr<restbed::Session> session, const restbed::Bytes & body) + { + std::string data(std::begin(body), std::end(body)); + + std::map<std::string, std::string> shortcutsMap = parsePost(data); + RING_DBG("shortcutsMap received"); + for(auto& it : shortcutsMap) + RING_DBG("%s : %s", it.first.c_str(), it.second.c_str()); + + DRing::setShortcuts(shortcutsMap); + + session->close(restbed::OK); + }); +} + +void +RestConfigurationManager::setVolume(const std::string& device, const double& value) +{ + DRing::setVolume(device, value); +} + +void +RestConfigurationManager::getVolume(const std::string& device) +{ + //return DRing::getVolume(device); +} + +void +RestConfigurationManager::validateCertificate(const std::string& accountId, const std::string& certificate) +{ + //return DRing::validateCertificate(accountId, certificate); +} + +void +RestConfigurationManager::validateCertificatePath(const std::string& accountId, const std::string& certificate, const std::string& privateKey, const std::string& privateKeyPass, const std::string& caList) +{ + //return DRing::validateCertificatePath(accountId, certificate, privateKey, privateKeyPass, caList); +} + +void +RestConfigurationManager::getCertificateDetails(const std::string& certificate) +{ + //return DRing::getCertificateDetails(certificate); +} + +void +RestConfigurationManager::getCertificateDetailsPath(const std::string& certificate, const std::string& privateKey, const std::string& privateKeyPass) +{ + //return DRing::getCertificateDetailsPath(certificate, privateKey, privateKeyPass); +} + +void +RestConfigurationManager::getPinnedCertificates() +{ + //return DRing::getPinnedCertificates(); +} + +void +RestConfigurationManager::pinCertificate(const std::vector<uint8_t>& certificate, const bool& local) +{ + //return DRing::pinCertificate(certificate, local); +} + +void +RestConfigurationManager::pinCertificatePath(const std::string& certPath) +{ + //return DRing::pinCertificatePath(certPath); +} + +void +RestConfigurationManager::unpinCertificate(const std::string& certId) +{ + //return DRing::unpinCertificate(certId); +} + +void +RestConfigurationManager::unpinCertificatePath(const std::string& p) +{ + //return DRing::unpinCertificatePath(p); +} + +void +RestConfigurationManager::pinRemoteCertificate(const std::string& accountId, const std::string& certId) +{ + //return DRing::pinRemoteCertificate(accountId, certId); +} + +void +RestConfigurationManager::setCertificateStatus(const std::string& accountId, const std::string& certId, const std::string& status) +{ + //return DRing::setCertificateStatus(accountId, certId, status); +} + +void +RestConfigurationManager::getCertificatesByStatus(const std::string& accountId, const std::string& status) +{ + //return DRing::getCertificatesByStatus(accountId, status); +} + +void +RestConfigurationManager::getTrustRequests(const std::shared_ptr<restbed::Session> session) +{ + //return DRing::getTrustRequests(accountId); +} + +void +RestConfigurationManager::acceptTrustRequest(const std::string& accountId, const std::string& from) +{ + //return DRing::acceptTrustRequest(accountId, from); +} + +void +RestConfigurationManager::discardTrustRequest(const std::string& accountId, const std::string& from) +{ + //return DRing::discardTrustRequest(accountId, from); +} + +void +RestConfigurationManager::sendTrustRequest(const std::string& accountId, const std::string& to, const std::vector<uint8_t>& payload) +{ + DRing::sendTrustRequest(accountId, to, payload); +} + +void +RestConfigurationManager::exportAccounts(const std::vector<std::string>& accountIDs, const std::string& filepath, const std::string& password) +{ + //return DRing::exportAccounts(accountIDs, filepath, password); +} + +void +RestConfigurationManager::importAccounts(const std::string& archivePath, const std::string& password) +{ + //return DRing::importAccounts(archivePath, password); +} diff --git a/bin/restcpp/restconfigurationmanager.h b/bin/restcpp/restconfigurationmanager.h new file mode 100644 index 0000000000000000000000000000000000000000..1c80ea2a25c9e8bc697156bd39552497823fc9cc --- /dev/null +++ b/bin/restcpp/restconfigurationmanager.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2016 Savoir-faire Linux Inc. + * + * Author: Simon Zeni <simon.zeni@savoirfairelinux.com> + * + * 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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#pragma once + +#include <vector> +#include <map> +#include <string> +#include <regex> +#include <restbed> + +#if __GNUC__ >= 5 || (__GNUC__ >=4 && __GNUC_MINOR__ >= 6) +/* This warning option only exists for gcc 4.6.0 and greater. */ +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#endif + +#include "dring/dring.h" +#include "dring/callmanager_interface.h" +#include "dring/configurationmanager_interface.h" +#include "dring/presencemanager_interface.h" +#ifdef RING_VIDEO +#include "dring/videomanager_interface.h" +#endif +#include "logger.h" +#include "im/message_engine.h" + +#pragma GCC diagnostic warning "-Wignored-qualifiers" + +#if __GNUC__ >= 5 || (__GNUC__ >=4 && __GNUC_MINOR__ >= 6) +/* This warning option only exists for gcc 4.6.0 and greater. */ +#pragma GCC diagnostic warning "-Wunused-but-set-variable" +#endif + +class RestConfigurationManager +{ + public: + RestConfigurationManager(); + + std::vector<std::shared_ptr<restbed::Resource>> getResources(); + + private: + // Attributes + std::vector<std::shared_ptr<restbed::Resource>> resources_; + + // Methods + std::map<std::string, std::string> parsePost(const std::string& post); + void populateResources(); + void defaultRoute(const std::shared_ptr<restbed::Session> session); + + void getAccountDetails(const std::shared_ptr<restbed::Session> session); + void getVolatileAccountDetails(const std::shared_ptr<restbed::Session> session); + void setAccountDetails(const std::shared_ptr<restbed::Session> session); + void setAccountActive(const std::shared_ptr<restbed::Session> session); + void getAccountTemplate(const std::shared_ptr<restbed::Session> session); + void addAccount(const std::shared_ptr<restbed::Session> session); + void removeAccount(const std::shared_ptr<restbed::Session> session); + void getAccountList(const std::shared_ptr<restbed::Session> session); + void sendRegister(const std::shared_ptr<restbed::Session> session); + void registerAllAccounts(const std::shared_ptr<restbed::Session> session); + void sendTextMessage(const std::shared_ptr<restbed::Session> session); + void getMessageStatus(const std::shared_ptr<restbed::Session> session); + void getTlsDefaultSettings(const std::shared_ptr<restbed::Session> session); + void getCodecList(const std::shared_ptr<restbed::Session> session); + void getSupportedTlsMethod(const std::shared_ptr<restbed::Session> session); + void getSupportedCiphers(const std::shared_ptr<restbed::Session> session); + void getCodecDetails(const std::shared_ptr<restbed::Session> session); + void setCodecDetails(const std::shared_ptr<restbed::Session> session); + void getActiveCodecList(const std::shared_ptr<restbed::Session> session); + void setActiveCodecList(const std::string& accountID, const std::vector<unsigned>& list); // /!\ not implemented + void getAudioPluginList(const std::shared_ptr<restbed::Session> session); + void setAudioPlugin(const std::shared_ptr<restbed::Session> session); + void getAudioOutputDeviceList(const std::shared_ptr<restbed::Session> session); + void setAudioOutputDevice(const std::shared_ptr<restbed::Session> session); + void setAudioInputDevice(const std::shared_ptr<restbed::Session> session); + void setAudioRingtoneDevice(const std::shared_ptr<restbed::Session> session); + void getAudioInputDeviceList(const std::shared_ptr<restbed::Session> session); + void getCurrentAudioDevicesIndex(const std::shared_ptr<restbed::Session> session); + void getAudioInputDeviceIndex(const std::shared_ptr<restbed::Session> session); + void getAudioOutputDeviceIndex(const std::shared_ptr<restbed::Session> session); + void getCurrentAudioOutputPlugin(const std::shared_ptr<restbed::Session> session); + void getNoiseSuppressState(const std::shared_ptr<restbed::Session> session); + void setNoiseSuppressState(const std::shared_ptr<restbed::Session> session); + void isAgcEnabled(const std::shared_ptr<restbed::Session> session); + void setAgcState(const std::shared_ptr<restbed::Session> session); + void muteDtmf(const std::shared_ptr<restbed::Session> session); + void isDtmfMuted(const std::shared_ptr<restbed::Session> session); + void isCaptureMuted(const std::shared_ptr<restbed::Session> session); + void muteCapture(const std::shared_ptr<restbed::Session> session); + void isPlaybackMuted(const std::shared_ptr<restbed::Session> session); + void mutePlayback(const std::shared_ptr<restbed::Session> session); + void isRingtoneMuted(const std::shared_ptr<restbed::Session> session); + void muteRingtone(const std::shared_ptr<restbed::Session> session); + void getAudioManager(const std::shared_ptr<restbed::Session> session); + void setAudioManager(const std::shared_ptr<restbed::Session> session); + void getSupportedAudioManagers(const std::shared_ptr<restbed::Session> session); + void getRecordPath(const std::shared_ptr<restbed::Session> session); + void setRecordPath(const std::shared_ptr<restbed::Session> session); + void getIsAlwaysRecording(const std::shared_ptr<restbed::Session> session); + void setIsAlwaysRecording(const std::shared_ptr<restbed::Session> session); + void setHistoryLimit(const std::shared_ptr<restbed::Session> session); + void getHistoryLimit(const std::shared_ptr<restbed::Session> session); + void setAccountsOrder(const std::shared_ptr<restbed::Session> session); + void getHookSettings(const std::shared_ptr<restbed::Session> session); + void setHookSettings(const std::shared_ptr<restbed::Session> session); + void getCredentials(const std::shared_ptr<restbed::Session> session); + void setCredentials(const std::shared_ptr<restbed::Session> session); + void getAddrFromInterfaceName(const std::shared_ptr<restbed::Session> session); + void getAllIpInterface(const std::shared_ptr<restbed::Session> session); + void getAllIpInterfaceByName(const std::shared_ptr<restbed::Session> session); + void getShortcuts(const std::shared_ptr<restbed::Session> session); + void setShortcuts(const std::shared_ptr<restbed::Session> session); + void setVolume(const std::string& device, const double& value); + void getVolume(const std::string& device); + void validateCertificate(const std::string& accountId, const std::string& certificate); + void validateCertificatePath(const std::string& accountId, const std::string& certificatePath, const std::string& privateKey, const std::string& privateKeyPass, const std::string& caList); + void getCertificateDetails(const std::string& certificate); + void getCertificateDetailsPath(const std::string& certificatePath, const std::string& privateKey, const std::string& privateKeyPass); + void getPinnedCertificates(); + void pinCertificate(const std::vector<uint8_t>& certificate, const bool& local); + void unpinCertificate(const std::string& certId); + void pinCertificatePath(const std::string& path); + void unpinCertificatePath(const std::string& path); + void pinRemoteCertificate(const std::string& accountId, const std::string& certId); + void setCertificateStatus(const std::string& account, const std::string& certId, const std::string& status); + void getCertificatesByStatus(const std::string& account, const std::string& status); + void getTrustRequests(const std::shared_ptr<restbed::Session> session); + void acceptTrustRequest(const std::string& accountId, const std::string& from); + void discardTrustRequest(const std::string& accountId, const std::string& from); + void sendTrustRequest(const std::string& accountId, const std::string& to, const std::vector<uint8_t>& payload); + void exportAccounts(const std::vector<std::string>& accountIDs, const std::string& filepath, const std::string& password); + void importAccounts(const std::string& archivePath, const std::string& password); +}; diff --git a/bin/restcpp/restvideomanager.cpp b/bin/restcpp/restvideomanager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bdbc967818830b3bc167a71a26dfaac3920b21e3 --- /dev/null +++ b/bin/restcpp/restvideomanager.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2016 Savoir-faire Linux Inc. + * + * Author: Simon Zeni <simon.zeni@savoirfairelinux.com> + * + * 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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include "restvideomanager.h" +#include "client/videomanager.h" + +RestVideoManager::RestVideoManager() : + resources_() +{ + populateResources(); +} + +std::vector<std::shared_ptr<restbed::Resource>> +RestVideoManager::getResources() +{ + return resources_; +} + +// Private + +std::map<std::string, std::string> +RestVideoManager::parsePost(const std::string& post) +{ + std::map<std::string, std::string> data; + + auto split = [](const std::string& s, char delim){ + std::vector<std::string> v; + auto i = 0; + auto pos = s.find(delim); + while (pos != std::string::npos) + { + v.push_back(s.substr(i, pos-i)); + i = ++pos; + pos = s.find(delim, pos); + + if (pos == std::string::npos) + v.push_back(s.substr(i, s.length())); + } + + return v; + }; + + if(post.find_first_of('&') != std::string::npos) + { + std::vector<std::string> v = split(post, '&'); + + for(auto& it : v) + { + std::vector<std::string> tmp = split(it, '='); + data[tmp.front()] = tmp.back(); + } + } + else + { + std::vector<std::string> tmp = split(post, '='); + data[tmp.front()] = tmp.back(); + } + + return data; +} + +void +RestVideoManager::populateResources() +{ + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/videoManager"); + resources_.back()->set_method_handler("GET", + std::bind(&RestVideoManager::defaultRoute, this, std::placeholders::_1)); + + resources_.push_back(std::make_shared<restbed::Resource>()); + resources_.back()->set_path("/deviceList"); + resources_.back()->set_method_handler("GET", + std::bind(&RestVideoManager::getDeviceList, this, std::placeholders::_1)); +} + +void +RestVideoManager::defaultRoute(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /videoManager", session->get_origin().c_str()); + + std::string body = "Available routes are : \r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); +} + +void RestVideoManager::getDeviceList(const std::shared_ptr<restbed::Session> session) +{ + RING_INFO("[%s] GET /deviceList", session->get_origin().c_str()); + std::vector<std::string> list = DRing::getDeviceList(); + + std::string body = ""; + + for(auto& it : list) + body += it + "\r\n"; + + const std::multimap<std::string, std::string> headers + { + {"Content-Type", "text/html"}, + {"Content-Length", std::to_string(body.length())} + }; + + session->close(restbed::OK, body, headers); + +} + +void RestVideoManager::getCapabilities(const std::shared_ptr<restbed::Session> session) +{ + +} + +void RestVideoManager::getSettings(const std::shared_ptr<restbed::Session> session) +{ + +} + +void RestVideoManager::applySettings(const std::shared_ptr<restbed::Session> session) +{ + +} + +void RestVideoManager::setDefaultDevice(const std::shared_ptr<restbed::Session> session) +{ + +} + +void RestVideoManager::getDefaultDevice(const std::shared_ptr<restbed::Session> session) +{ + +} + +void RestVideoManager::startCamera(const std::shared_ptr<restbed::Session> session) +{ + +} + +void RestVideoManager::stopCamera(const std::shared_ptr<restbed::Session> session) +{ + +} + +void RestVideoManager::switchInput(const std::shared_ptr<restbed::Session> session) +{ + +} + +void RestVideoManager::hasCameraStarted(const std::shared_ptr<restbed::Session> session) +{ + +} diff --git a/bin/restcpp/restvideomanager.h b/bin/restcpp/restvideomanager.h new file mode 100644 index 0000000000000000000000000000000000000000..ac2e6067629c7d609ed0a0313c60806445ceb1ce --- /dev/null +++ b/bin/restcpp/restvideomanager.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 Savoir-faire Linux Inc. + * + * Author: Simon Zeni <simon.zeni@savoirfairelinux.com> + * + * 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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#pragma once + +#include <vector> +#include <map> +#include <string> +#include <restbed> + +#if __GNUC__ >= 5 || (__GNUC__ >=4 && __GNUC_MINOR__ >= 6) +/* This warning option only exists for gcc 4.6.0 and greater. */ +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#endif + +#include "dring/dring.h" +#include "dring/callmanager_interface.h" +#include "dring/configurationmanager_interface.h" +#include "dring/presencemanager_interface.h" +#ifdef RING_VIDEO +#include "dring/videomanager_interface.h" +#endif +#include "logger.h" + +#if __GNUC__ >= 5 || (__GNUC__ >=4 && __GNUC_MINOR__ >= 6) +/* This warning option only exists for gcc 4.6.0 and greater. */ +#pragma GCC diagnostic warning "-Wunused-but-set-variable" +#endif + +class RestVideoManager +{ + public: + RestVideoManager(); + + std::vector<std::shared_ptr<restbed::Resource>> getResources(); + + private: + // Attributes + std::vector<std::shared_ptr<restbed::Resource>> resources_; + + // Methods + std::map<std::string, std::string> parsePost(const std::string& post); + void populateResources(); + void defaultRoute(const std::shared_ptr<restbed::Session> session); + + void getDeviceList(const std::shared_ptr<restbed::Session> session); + void getCapabilities(const std::shared_ptr<restbed::Session> session); + void getSettings(const std::shared_ptr<restbed::Session> session); + void applySettings(const std::shared_ptr<restbed::Session> session); + void setDefaultDevice(const std::shared_ptr<restbed::Session> session); + void getDefaultDevice(const std::shared_ptr<restbed::Session> session); + void startCamera(const std::shared_ptr<restbed::Session> session); + void stopCamera(const std::shared_ptr<restbed::Session> session); + void switchInput(const std::shared_ptr<restbed::Session> session); + void hasCameraStarted(const std::shared_ptr<restbed::Session> session); +}; diff --git a/configure.ac b/configure.ac index b0884c1370acfefeaa24de8def75da057f3d660d..a744d013a235bcb29d95bd36f58c9bef4b2c8331 100644 --- a/configure.ac +++ b/configure.ac @@ -286,12 +286,12 @@ if test "${SYS}" = "linux"; then dnl Check for alsa development package - name: libasound2-dev ALSA_MIN_VERSION=1.0 AC_ARG_WITH([alsa], - [AS_HELP_STRING([--without-alsa], [disable support for alsa])], - [], - [with_alsa=yes]) + [AS_HELP_STRING([--without-alsa], [disable support for alsa])], + [], + [with_alsa=yes]) AS_IF([test "x$with_alsa" = "xyes"], [ PKG_CHECK_MODULES(ALSA, alsa >= ${ALSA_MIN_VERSION},, AC_MSG_ERROR([Missing alsa development files])) - ]); + ]); AC_DEFINE_UNQUOTED([HAVE_ALSA], `if test "x$with_alsa" = "xyes"; then echo 1; else echo 0; fi`, [Define if you have alsa]) fi @@ -386,6 +386,20 @@ AS_IF([test "x$with_dbus" = "xyes"], [ AM_CONDITIONAL(RING_DBUS, true)], AM_CONDITIONAL(RING_DBUS, false)); +# Rest C++ with restbed +AC_ARG_WITH([restcpp], + AS_HELP_STRING([--with-restcpp], [enable rest support with C++])) + +AS_IF([test "x$with_restcpp" = "xyes"], [ + PKG_CHECK_MODULES(RESTBED, librestbed,, AC_MSG_WARN([Missing restbed files])) + + AS_AC_EXPAND(SBINDIR, $sbindir) + AC_SUBST(SBINDIR) + + AC_CONFIG_FILES([bin/restcpp/Makefile]) + + AM_CONDITIONAL(RING_RESTCPP, true)], + AM_CONDITIONAL(RING_RESTCPP, false)); dnl Check for libav PKG_CHECK_MODULES(LIBAVCODEC, libavcodec >= 53.5.0,, AC_MSG_ERROR([Missing libavcodec development files])) @@ -548,7 +562,7 @@ AS_IF([test "x$with_natpmp" != xno], AC_DEFINE_UNQUOTED([HAVE_LIBNATPMP], `if test "x$with_natpmp" != xno; then echo 1; else echo 0; fi`, [Define if you have libnatpmp]) AC_DEFINE_UNQUOTED([HAVE_SHM], `if test -z "${HAVE_LINUX_TRUE}" && test -z "${HAVE_ANDROID_FALSE}" ; then echo 1; else echo 0; fi`, - [Define if you have shared memory support]) + [Define if you have shared memory support]) # DOXYGEN # required dependency(ies): doxygen diff --git a/contrib/src/restbed/CMakeLists.patch b/contrib/src/restbed/CMakeLists.patch new file mode 100644 index 0000000000000000000000000000000000000000..94128ded8180d133540eed52ca7ffb5f7bbbb758 --- /dev/null +++ b/contrib/src/restbed/CMakeLists.patch @@ -0,0 +1,10 @@ +--- CMakeLists.txt 2016-06-13 12:01:30.415787179 -0400 ++++ CMakeLists.txt 2016-06-13 12:01:33.329120391 -0400 +@@ -71,5 +71,5 @@ + install( FILES "${INCLUDE_DIR}/${PROJECT_NAME}" DESTINATION "include" ) + install( FILES ${BUILD_ARTIFACTS} DESTINATION "include/corvusoft/${PROJECT_NAME}" ) + install( TARGETS ${PROJECT_NAME} +- LIBRARY DESTINATION "library" +- ARCHIVE DESTINATION "library" COMPONENT library ) ++ LIBRARY DESTINATION "lib" ++ ARCHIVE DESTINATION "lib" COMPONENT library ) diff --git a/contrib/src/restbed/conditional_sslv3.patch b/contrib/src/restbed/conditional_sslv3.patch new file mode 100644 index 0000000000000000000000000000000000000000..fcba853b92021704f4d98f4292de9cf3957bd2bc --- /dev/null +++ b/contrib/src/restbed/conditional_sslv3.patch @@ -0,0 +1,29 @@ +Description: Conditionalize SSLv3 support for OpenSSL +Author: Markus Wanner <markus@bluegap.ch> +Forwarded: no + +--- a/include/asio/ssl/impl/context.ipp ++++ b/include/asio/ssl/impl/context.ipp +@@ -88,6 +88,14 @@ + handle_ = ::SSL_CTX_new(::SSLv2_server_method()); + break; + #endif // defined(OPENSSL_NO_SSL2) ++#if defined(OPENSSL_NO_SSL3) ++ case context::sslv3: ++ case context::sslv3_client: ++ case context::sslv3_server: ++ asio::detail::throw_error( ++ asio::error::invalid_argument, "context"); ++ break; ++#else // defined(OPENSSL_NO_SSL3) + case context::sslv3: + handle_ = ::SSL_CTX_new(::SSLv3_method()); + break; +@@ -97,6 +105,7 @@ + case context::sslv3_server: + handle_ = ::SSL_CTX_new(::SSLv3_server_method()); + break; ++#endif + case context::tlsv1: + handle_ = ::SSL_CTX_new(::TLSv1_method()); + break; diff --git a/contrib/src/restbed/rules.mak b/contrib/src/restbed/rules.mak new file mode 100644 index 0000000000000000000000000000000000000000..cb69fe91abf7510a72ca9af3ee3ac339f9ab7fce --- /dev/null +++ b/contrib/src/restbed/rules.mak @@ -0,0 +1,49 @@ +# +# Copyright (C) 2016 Savoir-faire Linux Inc. +# +# Author: Simon Zeni <simon.zeni@savoirfairelinux.com> +# +# 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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +RESTBED_VERSION := 4.0 +RESTBED_URL := https://github.com/Corvusoft/restbed/archive/$(RESTBED_VERSION).tar.gz + +ifeq ($(call need_pkg,"restbed >= 4.0"),) +PKGS_FOUND += restbed +endif + +$(TARBALLS)/restbed-$(RESTBED_VERSION).tar.gz: + $(call download,$(RESTBED_URL)) + +RESTBED_CONF = -DBUILD_TESTS=NO \ + -DBUILD_EXAMPLES=NO \ + -DBUILD_SSL=NO \ + -DBUILD_SHARED=NO \ + -DCMAKE_C_COMPILER=gcc \ + -DCMAKE_CXX_COMPILER=g++ \ + -DCMAKE_INSTALL_PREFIX=$(PREFIX) + +restbed: restbed-$(RESTBED_VERSION).tar.gz + $(UNPACK) + git clone https://github.com/Corvusoft/asio-dependency.git $(UNPACK_DIR)/dependency/asio/ + cd $(UNPACK_DIR)/dependency/asio/asio && patch -fp1 < ../../../../../src/restbed/conditional_sslv3.patch + cd $(UNPACK_DIR)/ && ls && patch -p0 < ../../src/restbed/CMakeLists.patch + $(MOVE) + +.restbed: restbed + cd $< && cmake $(RESTBED_CONF) . + cd $< && $(MAKE) install + touch $@